1. 分析下继承关系:
    2. 1ThreadPoolTaskExecutor extends (2)ExecutorConfigurationSupport
    3. implements (3)AsyncListenableTaskExecutor, (4)SchedulingTaskExecutor
    4. 2 ExecutorConfigurationSupport extends CustomizableThreadFactory implements BeanNameAware, InitializingBean, DisposableBean
    5. 3public interface AsyncListenableTaskExecutor extends AsyncTaskExecutor
    6. 4public interface SchedulingTaskExecutor extends AsyncTaskExecutor
    7. 从上继承关系可知:
    8. ThreadPoolExecutor是一个java类不提供spring生命周期和参数装配。
    9. ThreadPoolTaskExecutor实现了InitializingBean, DisposableBean xxaware等,具有spring特性
    10. AsyncListenableTaskExecutor提供了监听任务方法(相当于添加一个任务监听,提交任务完成都会回调该方法)
    11. 简单理解:
    12. 1ThreadPoolTaskExecutor使用ThreadPoolExecutor并增强,扩展了更多特性
    13. 2ThreadPoolTaskExecutor只关注自己增强的部分,任务执行还是ThreadPoolExecutor处理。
    14. 3、前者spring自己用着爽,后者离开spring我们用ThreadPoolExecutor爽。
    15. 注意:ThreadPoolTaskExecutor 不会自动创建ThreadPoolExecutor需要手动调initialize才会创建
    16. 如果@Bean 就不需手动,会自动InitializingBeanafterPropertiesSet来调initialize`

    spring中的线程池加强和封装了原生threadpoolexecutor的特性,使之更加自然

    1. @Configuration
    2. @EnableAsync
    3. public class ExecutorConfig {
    4. private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);
    5. @Bean
    6. public Executor asyncServiceExecutor() {
    7. logger.info("start asyncServiceExecutor");
    8. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    9. //配置核心线程数
    10. executor.setCorePoolSize(5);
    11. //配置最大线程数
    12. executor.setMaxPoolSize(5);
    13. //配置队列大小
    14. executor.setQueueCapacity(99999);
    15. //配置线程池中的线程的名称前缀
    16. executor.setThreadNamePrefix("async-service-");
    17. // rejection-policy:当pool已经达到max size的时候,如何处理新任务
    18. // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
    19. executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    20. //执行初始化
    21. executor.initialize();
    22. return executor;
    23. }
    24. }
    • 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
    • 如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
    • 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maxPoolSize,建新的线程来处理被添加的任务。
    • 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maxPoolSize,那么通过handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程 maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
    • 当线程池中的线程数量大于corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

    编写接口以及实现接口
    函数式接口,用于添加一个函数(名字未知)
    异步调用接口,用于接口的继承(推荐加上)

    1. @FunctionalInterface
    2. public interface ExecutorFunctional {
    3. void execute() throws Exception;
    4. }
    5. public interface AsyncService {
    6. void executeAsync(ExecutorFunctional target);
    7. }
    8. @Service
    9. public class AsyncServiceImpl implements AsyncService {
    10. @Override
    11. @Async("asyncServiceExecutor")
    12. public void executeAsync(ExecutorFunctional target) {
    13. try {
    14. //这个execute中有一堆语句,我们可以将我们想要的任意类型的语句都写进去
    15. //因为这是执行接口的调用,内部的语句需要自行书写
    16. target.execute();
    17. } catch (Exception e) {
    18. e.printStackTrace();
    19. }
    20. }
    21. }
    22. //看起来就像是把一堆语句交给线程池执行了,不是吗?
    23. //我们只需要关注关注语句本身就行了
    24. @GetMapping("func")
    25. public void testFunctionalExecutor() {
    26. // CountDownLatch latch = new CountDownLatch(3);
    27. for (int i = 0; i < 3; i++) {
    28. asyncService.executeAsync(() -> {
    29. int random = (int) (2 + Math.random() * 8);
    30. log.info("线程睡{}秒", random);
    31. Thread.sleep(random * 1000);
    32. // latch.countDown();
    33. log.info("子线程睡{}秒,执行完毕", random);
    34. });
    35. }
    36. // latch.await();
    37. log.info("主线程执行完毕");
    38. }

    使用线程池的时候,先用@Async(“线程配置命名”)来让spring来说明想要进入哪一个线程池

    线程拒绝策略
    当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
    ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。
    ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务 ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务

    线程池的默认拒绝策略为AbortPolicy,即丢弃任务并抛出RejectedExecutionException异常。

    (1)AbortPolicy
    AbortPolicy
    ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

    1. A handler for rejected tasks that throws a {@code RejectedExecutionException}.

    这是线程池默认的拒绝策略,在任务不能再提交的时候,抛出异常,及时反馈程序运行状态。如果是比较关键的业务,推荐使用此拒绝策略,这样子在系统不能承载更大的并发量的时候,能够及时的通过异常发现。

    (2)DiscardPolicy
    ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃。

    1. A handler for rejected tasks that silently discards therejected task.

    使用此策略,可能会使我们无法发现系统的异常状态。建议是一些无关紧要的业务采用此策略。例如,本人的博客网站统计阅读量就是采用的这种拒绝策略。

    (3)DiscardOldestPolicy
    ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务。

    1. A handler for rejected tasks that discards the oldest unhandled request and then retries {@code execute}, unless the executor is shut down, in which case the task is discarded.

    此拒绝策略,是一种喜新厌旧的拒绝策略。是否要采用此种拒绝策略,还得根据实际业务是否允许丢弃老任务来认真衡量。

    (4)CallerRunsPolicy
    ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

    1. 1. A handler for rejected tasks that runs the rejected task directly in the calling thread of the {@code execute} method, unless the executor has been shut down, in which case the task is discarded.
    2. 2.

    如果任务被拒绝了,则由调用线程(提交任务的线程)直接执行此任务,我们可以通过代码来验证这一点: