导航:更多的spring注解标签点击这里
@EnableAsync
开启异步任务支持。注解在配置类上,这个没什么好说的
,可能有的人会问,开启一个子线程的话,我们通过new Thread 或者实现runnable就可以了,为什么要用到这里
其实一般情况下也是如果
EnableAsync是可以提供线程池的,我们需要实现AsyncConfigurer接口才有意义,如果不实现的话那么就和new Thread或者实现runnable接口一样的
使用示例:
@EnableAsync
public class Test implements AsyncConfigurer {
}
我们来看一下AsyncConfigurer 接口的源码
如上图所示,他只提供了2个方法
getAsyncExecutor方法是执行方法,返回线程池的一些信息, getAsyncUncaughtExceptionHandler则是发生了异常应该处理的方方法 具体配置如下所示:
@EnableAsync
public class Test implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
// TODO Auto-generated method stub
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池数量,方法: 返回可用处理器的Java虚拟机的数量。
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
//最大线程数量
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors()*5);
//线程池的队列容量
executor.setQueueCapacity(Runtime.getRuntime().availableProcessors()*2);
//线程名称的前缀
executor.setThreadNamePrefix("this-excutor-");
// setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
//executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
/*异步任务中异常处理*/
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
由于代码中注释已经很详细了,这里我就不再次阐述了
@Async
注解在方法上标示这是一个异步方法,在类上标示这个类所有的方法都是异步方法,执行线程池就是我们上面配置的
这个也没有什么好说的,使用如下所示
@Component
public class TreadTasks {
@Async
public void startMyTreadTask() {
System.out.println("这是一个异步线程");
}
}
使用也很简单,如下所示
@RestController
public class Web {
@Autowired
private TreadTasks treadTasks;
@RequestMapping("a123")
public String aaa(){
treadTasks.startMyTreadTask();
return "111111";
}
}
执行效果如下所示
这个线程池是不是非常简单?
确实是很简单,网上绝大部分都是这么说的,但是呢,这里面有一个有意思的问题,那就是这么做其实是错误的
这样写并不是一个异步线程,而是同一个线程,下面我们就来证明一下这个错误,我们修改一下代码,如下所示
运行测试一下
我们可以看到,两个线程的id是一模一样的,根本就不是一个异步线程,如果还不信的话我们看看下面的代码
加了一个打印语句
线程等待一会在执行
我们可以看到,虚拟机数量那一句根本没有打印,而且先打印了异步线程id,说明这并不是一个异步。
那么到底是怎么回事呢?spring提供的有问题?
当然不是,因为EnableAsync标签根本就不是一个全局的标签,他和@RestController类似,只是表明本类而已,所以我们需要把EnableAsync放到具体的类上才是一个正确的异步,如下所示
而且线程池需要的标签也不是EnableAsync,而是Component
这样才是正确的,执行效果如下所示
我们可以看到,打印了虚拟机的数量,而且两个线程的id也不一样