举例场景:当用户支付成功之后,需要马上通知商家(发短信或者语音提示功能等),然后再处理其他业务,如果按照正常逻辑,同步执行,当通知商家这个步骤响应很慢,则后面逻辑就需要等待它执行完毕后才能继续走下去。这样子,我们就可以用线程去异步处理,而我们在项目中,如果直接新建线程,可能会造成很大的开销。所以,优先使用线程池(由于多线程这一块我本人也不是非常的熟悉,有错误请各位大佬提出)
第一步:定义线程池
@Configuration
@EnableAsync
public class TaskExecutePool {
@Bean("myAsyncPool")
public Executor myTaskAsyncPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程数:线程池创建时候初始化的线程数
executor.setCorePoolSize(5);
//最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(10);
//缓冲队列:用来缓冲执行任务的队列
executor.setQueueCapacity(10);
//允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
//线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
executor.setThreadNamePrefix("MyExecutor-");
// 当pool已经达到max size的时候,如何处理新任务
// 这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,
// 该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;
// 如果执行程序已关闭,则会丢弃该任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
每个配置注释已经很清楚了,setRejectedExecutionHandler这里的话,RejectedExecutionHandler提供了四种方式来处理,这个看你业务去选择
- ThreadPoolExecutor.AbortPolicy() 抛出java.util.concurrent.RejectedExecutionException异常
- ThreadPoolExecutor.CallerRunsPolicy() 重试添加当前的任务,他会自动重复调用execute()方法
- ThreadPoolExecutor.DiscardOldestPolicy() 抛弃旧的任务
- ThreadPoolExecutor.DiscardPolicy() 抛弃当前的任务
第二步:如何使用
使用非常简单,只需要在@Async
注解中指定线程池名就可以了
@Component
public class ThreadTask {
Logger log = LoggerFactory.getLogger(ThreadTask.class);
public static Random random = new Random();
SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
@Async(value="myAsyncPool")
public void testTask(int i) throws Exception{
System.out.println(Thread.currentThread().getName()+"--"+i +"--时间:"+ format.format(new Date()));
Thread.sleep(3000);
}
}
第三步:测试
直接注入ThreadTask
@RunWith(SpringRunner.class)
@SpringBootTest
public class AppTest{
@Autowired
private ThreadTask threadTask;
@Test
public void testThread() throws Exception{
//模拟高并发
for (int i=0;i<50;i++){
threadTask.testTask(i);
}
}
}
运行结果
总结
上面看得出,在同一时间,执行了11次,但是我们设置了最大线程数是10,那就是一次性最多只能有10个线程运行,另外的在等待中,,为什么会有11次执行呢,因为缓冲队列也是10,等待的线程数已经超过了队列长度,所以,最新的线程将由主线程去执行,就是main方法所在线程。