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