举例场景:当用户支付成功之后,需要马上通知商家(发短信或者语音提示功能等),然后再处理其他业务,如果按照正常逻辑,同步执行,当通知商家这个步骤响应很慢,则后面逻辑就需要等待它执行完毕后才能继续走下去。这样子,我们就可以用线程去异步处理,而我们在项目中,如果直接新建线程,可能会造成很大的开销。所以,优先使用线程池(由于多线程这一块我本人也不是非常的熟悉,有错误请各位大佬提出)

 

第一步:定义线程池

@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提供了四种方式来处理,这个看你业务去选择

  1. ThreadPoolExecutor.AbortPolicy()  抛出java.util.concurrent.RejectedExecutionException异常 
  2. ThreadPoolExecutor.CallerRunsPolicy() 重试添加当前的任务,他会自动重复调用execute()方法 
  3. ThreadPoolExecutor.DiscardOldestPolicy() 抛弃旧的任务 
  4. 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);
        }
    }

}

运行结果

springboot 异步多线程 等待结果 springboot配置异步线程池_线程池

总结

上面看得出,在同一时间,执行了11次,但是我们设置了最大线程数是10,那就是一次性最多只能有10个线程运行,另外的在等待中,,为什么会有11次执行呢,因为缓冲队列也是10,等待的线程数已经超过了队列长度,所以,最新的线程将由主线程去执行,就是main方法所在线程。