0
点赞
收藏
分享

微信扫一扫

线程池使用方式

@Async+自定义线程池配置类

重新实现接口AsyncConfigurer。

@Configuration
 public class AsyncConfiguration implements AsyncConfigurer {
     @Bean("kingAsyncExecutor")
     public ThreadPoolTaskExecutor executor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         int corePoolSize = 10;
         executor.setCorePoolSize(corePoolSize);
         int maxPoolSize = 50;
         executor.setMaxPoolSize(maxPoolSize);
         int queueCapacity = 10;
         executor.setQueueCapacity(queueCapacity);
         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
         String threadNamePrefix = "kingDeeAsyncExecutor-";
         executor.setThreadNamePrefix(threadNamePrefix);
         executor.setWaitForTasksToCompleteOnShutdown(true);
         // 使用自定义的跨线程的请求级别线程工厂类19         int awaitTerminationSeconds = 5;
         executor.setAwaitTerminationSeconds(awaitTerminationSeconds);
         executor.initialize();
         return executor;
     }
 
     @Override
     public Executor getAsyncExecutor() {
         return executor();
     }
 
     @Override
     public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
         return (ex, method, params) -> ErrorLogger.getInstance().log(String.format("执行异步任务'%s'", method), ex);
     }
 }

继承AsyncConfigurerSupport

@Configuration  
@EnableAsync  
class SpringAsyncConfigurer extends AsyncConfigurerSupport {  
  
    @Bean  
    public ThreadPoolTaskExecutor asyncExecutor() {  
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();  
        threadPool.setCorePoolSize(3);  
        threadPool.setMaxPoolSize(3);  
        threadPool.setWaitForTasksToCompleteOnShutdown(true);  
        threadPool.setAwaitTerminationSeconds(60 * 15);  
        return threadPool;  
    }  
  
    @Override  
    public Executor getAsyncExecutor() {  
        return asyncExecutor;  
	}  

  @Override  
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() 	{
	    return (ex, method, params) -> ErrorLogger.getInstance().log(String.format("执行异步任务'%s'", method), ex);
	}
}

配置由自定义的TaskExecutor替代内置的任务执行器

@EnableAsync
 @Configuration
 public class TaskPoolConfig {
     @Bean(name = AsyncExecutionAspectSupport.DEFAULT_TASK_EXECUTOR_BEAN_NAME)
     public Executor taskExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
          //核心线程池大小
         executor.setCorePoolSize(10);
         //最大线程数
         executor.setMaxPoolSize(20);
         //队列容量
         executor.setQueueCapacity(200);
         //活跃时间
         executor.setKeepAliveSeconds(60);
         //线程名字前缀
         executor.setThreadNamePrefix("taskExecutor-");
         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
         return executor;
     }
    @Bean(name = "new_task")
     public Executor taskExecutor() {
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
          //核心线程池大小
         executor.setCorePoolSize(10);
         //最大线程数
         executor.setMaxPoolSize(20);
         //队列容量
         executor.setQueueCapacity(200);
         //活跃时间
         executor.setKeepAliveSeconds(60);
         //线程名字前缀
         executor.setThreadNamePrefix("taskExecutor-");
         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
         return executor;
     }
 }

@Async失效情况

  • 异步方法使用static修饰
  • 异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
  • 异步方法不能与被调用的异步方法在同一个类中
  • 类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
  • 如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解

@Async使用场景

@Async注解的主要作用是实现异步方法调用,它可以将一个方法的执行委托给一个线程池中的线程来异步执行,从而不会阻塞当前线程。

@Async的实际使用场景包括但不限于以下几个方面:

  1. 提高系统的并发能力:通过将耗时的操作异步化,可以提高系统的并发能力。例如,在一个Web应用程序中,可以将一些耗时的操作(如发送邮件、生成报表等)标记为@Async,这样可以避免阻塞主线程,提高系统的吞吐量。
  2. 提升用户体验:在一些需要耗时操作的场景下,如上传文件、数据处理等,可以使用@Async来实现异步处理,从而提升用户体验。用户可以继续进行其他操作,而不需要等待耗时操作的完成。
  3. 避免阻塞调用方:有时候,某个方法的调用方不希望等待方法的执行结果,而是希望立即返回。使用@Async可以将方法的执行转移到异步线程中,从而避免阻塞调用方。
  4. 并行执行任务:在某些场景下,需要同时执行多个任务,而不需要等待它们的执行结果。使用@Async可以将这些任务标记为异步方法,它们可以并行执行,从而提高效率。

注意

因为 Spring 在同一个类中的方法调用并不会通过代理对象来实现异步执行。在同一个类中,方法调用是直接的普通方法调用,而不会经过代理拦截。

因此,如果在同一个类中直接调用一个被@Async注解标记的异步方法,该方法会在当前线程中同步执行,而不会异步执行。这可能会影响到你期望异步执行的效果。

为了确保异步方法的异步执行,应该通过将异步方法从同一个类中剥离出来,使用类的外部或其他类来调用异步方法。这样,Spring 将会通过代理对象来截获异步方法的调用,并将其委托给异步线程池执行,从而实现异步执行的效果。

总结起来,如果在同一个类中直接调用异步方法,该方法会在当前线程中同步执行。为了实现异步执行的效果,应该通过类的外部或其他类来调用异步方法。

@Async+自定义线程+配置类

1、创建一个自定义的线程池类,继承自java.util.concurrent.ThreadPoolExecutor或实现java.util.concurrent.Executor接口,根据需求自定义线程池的配置,例如核心线程数、最大线程数、队列容量等。

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyThreadPool {
    private ThreadPoolExecutor executor;

    public MyThreadPool() {
        int corePoolSize = 10;
        int maxPoolSize = 20;
        int queueCapacity = 50;

        executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(queueCapacity));
    }

    public ThreadPoolExecutor getExecutor() {
        return executor;
    }
}

2、在Spring Boot的配置类中创建一个@Bean,返回自定义的线程池实例。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
    @Bean
    public MyThreadPool myThreadPool() {
        return new MyThreadPool();
    }
}

3、在需要异步执行的方法上使用@Async注解,并使用executor属性指定自定义的线程池。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class MyService {
    private MyThreadPool myThreadPool;

    @Autowired
    public MyService(MyThreadPool myThreadPool) {
        this.myThreadPool = myThreadPool;
    }

    @Async(executor = "myThreadPool")
    public void asyncMethod() {
        // 异步执行的逻辑
        // ...
    }
}

手动控制线程池

1、创建一个自定义的线程池类,可以继承自java.util.concurrent.ThreadPoolExecutor或实现java.util.concurrent.Executor接口,根据需求自定义线程池的配置。

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyThreadPool {
    private ThreadPoolExecutor executor;

    public MyThreadPool() {
        int corePoolSize = 10;
        int maxPoolSize = 20;
        int queueCapacity = 50;

        executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(queueCapacity));
    }

    public void execute(Runnable task) {
        executor.execute(task);
    }
}

2、在需要异步执行的方法中,创建一个实现了Runnable接口的任务,并将其提交给自定义线程池来执行。

public class MyClass {
    private MyThreadPool myThreadPool;

    public MyClass(MyThreadPool myThreadPool) {
        this.myThreadPool = myThreadPool;
    }

    public void myMethod() {
        // 创建一个实现了Runnable接口的任务
        Runnable task = () -> {
            // 异步执行的逻辑
            // ...
        };

        // 提交任务给自定义线程池执行
        myThreadPool.execute(task);
    }
}

举报

相关推荐

Java创建线程池的方式

SpringBoot 使用线程池

0 条评论