在原生java中,创建和启动线程的方式大致有以下几种:
- 继承Thread类,然后重写run方法
- 实现Runnable接口,并重写run方法
- 匿名内部类
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 线程实现
}
});
thread.start();
- lambda表达式
new Thread(()->{
// 线程实现
}).start();
在springboot中,推荐使用线程池的方式来管理多线程。
首先,添加配置类:
@Configuration
@EnableAsync
public class ThreadPoolConfig {
/**
* 核心线程池大小50
*/
private static final int CORE_POOL_SIZE = 10;
/**
* 最大可创建的线程数200
*/
private static final int MAX_POOL_SIZE = 10;
/**
* 队列最大长度1000
*/
private static final int QUEUE_CAPACITY = 10;
/**
* 线程池维护线程所允许的空闲时间300
*/
private static final int KEEP_ALIVE_SECONDS = 300;
/**
* 异步执行方法线程池
*
* @return
*/
@Bean(name = "asyncExecutor")
public ThreadPoolTaskExecutor eventExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(MAX_POOL_SIZE);
executor.setCorePoolSize(CORE_POOL_SIZE);
executor.setQueueCapacity(QUEUE_CAPACITY);
executor.setKeepAliveSeconds(KEEP_ALIVE_SECONDS);
// 线程池对拒绝任务(无线程可用)的处理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
这里需要特别注意类上的两个注解,@Configuration声明当前类为一个配置类,@EnableAsync开启对异步任务的支持。
接着,在service实现方法上添加注解@Async("asyncExecutor")
,这里的asyncExecutor对应config里面的执行器名称。
关于添加了@Async
注解,但是没事异步执行线程方法的情况貌似还有点多,主要是大家没有按照规范来使用,或者没有注意到一些细节点。
下面总结一些常见的易错点:
- 添加
@EnableAsync
注解,开启异步任务支持 - 异步方法必须是public且void(或Future)
- 异步方法所在的类必须添加@Component或者其它注解,加入到容器中
- 调用者与被调用者在同一个类中,且直接调用。这种情况和spring的事务一样,都是通过aop实现的,所以一定要用代理类的方法才能够实现。如果调用者和被调用者都在同一个类中,使用spring上下文,获取到对应的代理类再执行异步方法。