zoukankan      html  css  js  c++  java
  • SpringBoot 线程池配置 实现AsyncConfigurer接口方法

     目的是:
      通过实现AsyncConfigurer自定义线程池,包含异常处理
      实现AsyncConfigurer接口对异常线程池更加细粒度的控制
    *a) 创建线程自己的线程池
      b) 对void方法抛出的异常处理的类AsyncUncaughtExceptionHandler
     

    个人初步理解

     一、线程池是为突然大量爆发的线程设计的,通过有限的几个固定线程为大量的操作服务,减少了创建和销毁线程所需的时间,
    从而提高效率。如果一个线程的时间非常长,就没必要用线程池了(不是不能作长时间操作,而是不宜。),
    况且还不能控制线程池中线程的开始、挂起、和中止。
    二、利用线程池启动线程
    Thread udpThread = new Thread(udp);
    poolTaskExecutor.execute(udpThread);
    获取当前线程池活动的线程数:
    int count = poolTaskExecutor.getActiveCount();
    logger.debug("[x] - now threadpool active threads totalNum : " +count);
    三、配置解释
    当一个任务通过execute(Runnable)方法欲添加到线程池时:
    1、 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
    2、 如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
    3、如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
    4、 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
    也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程 maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
    5、 当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。
    allowCoreThreadTimeout:允许核心线程超时
    rejectedExecutionHandler:任务拒绝处理器

    两种情况会拒绝处理任务:
    当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务
    当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务
    线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常
    ThreadPoolExecutor类有几个内部实现类来处理这类情况:
    AbortPolicy 丢弃任务,抛运行时异常
    CallerRunsPolicy 执行任务
    DiscardPolicy 忽视,什么都不会发生
    DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务
    实现RejectedExecutionHandler接口,可自定义处理器

    废话不多说 上代码 环境:IDEA +SpringBoot+maven

       一、线程池配置类实现AsyncConfigurer 接口:

    @Component
    public class MyAsyncConfigurer implements AsyncConfigurer {
    
        private static final Logger log = LoggerFactory.getLogger(MyAsyncConfigurer.class);
    
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
            threadPool.setCorePoolSize(2);//当前线程数
            threadPool.setMaxPoolSize(120);// 最大线程数
            threadPool.setQueueCapacity(1);//线程池所使用的缓冲队列
            threadPool.setWaitForTasksToCompleteOnShutdown(true);//等待任务在关机时完成--表明等待所有线程执行完
            threadPool.setAwaitTerminationSeconds(60 * 15);// 等待时间 (默认为0,此时立即停止),并没等待xx秒后强制停止
            threadPool.setThreadNamePrefix("MyAsync-");//  线程名称前缀
            threadPool.initialize(); // 初始化
            System.out.println("--------------------------》》》开启异常线程池");
            return threadPool;
        }
    
    
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    
            return new MyAsyncExceptionHandler();
        }
    
        /**
         * 自定义异常处理类
         * @author hry
         *
         */
        class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
    
            //手动处理捕获的异常
            @Override
            public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
                System.out.println("-------------》》》捕获线程异常信息");
                log.info("Exception message - " + throwable.getMessage());
                log.info("Method name - " + method.getName());
                for (Object param : obj) {
                    log.info("Parameter value - " + param);
                }
            }
    
        }

        二、使用简单无参数异步线程进行测试

          

     @Override
        @Async
        public String asyncMethodWithVoidReturnType() {
    
            System.out.println("线程名称:"+Thread.currentThread().getName() + " be ready to read data!");
            try {
                Thread.sleep(1000 * 5);
                System.out.println("---------------------》》》无返回值延迟3秒:");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "已进入到异步";
        }

        三、0--3秒内连续访问如下结果

    线程名称:MyAsync-1 be ready to read data!
    线程名称:MyAsync-2 be ready to read data!
    线程名称:MyAsync-3 be ready to read data!
    线程名称:MyAsync-4 be ready to read data!
    线程名称:MyAsync-5 be ready to read data!
    线程名称:MyAsync-6 be ready to read data!
    线程名称:MyAsync-7 be ready to read data!
    线程名称:MyAsync-8 be ready to read data!
    MyAsync-1---------------------》》》无返回值延迟5秒:
    线程名称:MyAsync-1 be ready to read data!
    MyAsync-2---------------------》》》无返回值延迟5秒:
    线程名称:MyAsync-2 be ready to read data!
    MyAsync-3---------------------》》》无返回值延迟5秒:
    MyAsync-4---------------------》》》无返回值延迟5秒:
    MyAsync-5---------------------》》》无返回值延迟5秒:
    MyAsync-6---------------------》》》无返回值延迟5秒:
    MyAsync-7---------------------》》》无返回值延迟5秒:
    MyAsync-8---------------------》》》无返回值延迟5秒:
    MyAsync-1---------------------》》》无返回值延迟5秒:
    MyAsync-2---------------------》》》无返回值延迟5秒:

         如上可以看出 线程池发挥作用 多个线程访问如果超过核心线程数+队列数 变新创建线程,如果有线程

     空闲下来会继续分配,以此来提高效率。我是利用postMain 来进行的测试,以验证上面所说的理论问题。。

      实际应用中比这个复杂得多。。。。。。。。

         四、如果想要手动捕获异常信息  如下代码 即可

      throw new IllegalArgumentException(s);
    将上面代码 放在需要捕获信息的中
    在线程池配置中 MyAsyncExceptionHandler 的方法中 即会捕捉到信息。。。。。。



    收工。。。。。
  • 相关阅读:
    【寒假集训系列DAY.1】
    【专题系列】单调队列优化DP
    【DP悬线法】奶牛浴场
    [DP专题]悬线法
    【牛客网周赛32】个人解题思路
    【专题】概率期望DP
    牛客练习赛41D(思维转化)
    洛谷3199(01分数规划、判负环)
    洛谷4377(01分数规划)
    ZOJ3068(01分数规划)
  • 原文地址:https://www.cnblogs.com/memoryXudy/p/7737190.html
Copyright © 2011-2022 走看看