自定义线程池+countdownlatch

Posted 盖丽男

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义线程池+countdownlatch相关的知识,希望对你有一定的参考价值。

背景

要给前端出个接口,一个数据展示接口,要从好几个表把数据统计出来,所以打算用多线程来查,查完了返回给前端

用到的东西

就需求来说,join可以做到,countdownlatch也可以做到,我喜欢用countdownlatch做,代码看起来简单点,然后涉及到要开启多线程,所以还是自己来维护一个线程池来用。

代码

线程池部分

@Configuration
@EnableAsync //开启多线程
public class ThreadPoolConfig 
    private static final long serialVersionUID = -4778941758120026886L;


    /** 线程池维护线程的最少数量 */
    private int minPoolSize = 4;

    /** 线程池维护线程的最大数量 */
    private int maxPoolSize = 16;

    /** 线程池维护线程所允许的空闲时间 */
    private int idleSeconds = 1800;

    /** 线程池所使用的缓冲队列 */
    private int queueBlockSize = 30;

    private ThreadPoolExecutor executor;


    @Bean("taskExecutor")
    public Executor asyncServiceExecutor() 
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(minPoolSize);
        // 设置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        executor.setQueueCapacity(queueBlockSize);
        // 设置线程空闲时间,当超过核心线程之外的线程在空闲到达之后会被销毁(秒)
        executor.setKeepAliveSeconds(idleSeconds);
        // 设置默认线程名称
        executor.setThreadNamePrefix("ThreadExcutor");
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    

    public ThreadPoolConfig() 
        this.executor = new ThreadPoolExecutor(minPoolSize, maxPoolSize, idleSeconds,
                TimeUnit.SECONDS, /* 时间单位,秒 */
                new ArrayBlockingQueue<Runnable>(queueBlockSize),
                new ThreadPoolExecutor.CallerRunsPolicy()); /* 重试添加当前加入失败的任务 */
    

    public void execute(Runnable task) 
        executor.execute(task);
    

    public <T> Future<T> submit(Callable<T> task)
        return executor.submit(task);
    
 

countdownlatch代码

public QuotaInfoVo getQuotaInfo() 
        StopWatch sw = new StopWatch();
        sw.start();
        QuotaInfoVo info=new QuotaInfoVo();
        final CountDownLatch latch = new CountDownLatch(4);
    
        String id=tmpFcrmId; //这个是从配置文件拿的
        
        if (StringUtils.isEmpty(id))
            throw new ServiceException(ResultCode.ERROR);
        
        
        
        taskExecutor.execute(new Task1(info,latch,id));

        
        taskExecutor.execute(new Task2(info,latch,id));

        taskExecutor.execute(new Task3(info,latch,id));

        taskExecutor.execute(new Task4(info,latch,id));

        try 
            //主线程等待所有统计指标执行完毕
            latch.await(5, TimeUnit.SECONDS);
            //latch.await();
            sw.stop();
            log.info("getQuotaInfo finish ,total time is ",sw.getTotalTimeMillis());
         catch (InterruptedException e) 
            e.printStackTrace();
        
        return info;
    

然后给一个task的例子

private class Task1 implements Runnable

        private QuotaInfoVo quotaInfoVo;
        private CountDownLatch countDownLatch;
        private String id;
        public OrderCount(QuotaInfoVo quotaInfoVo,CountDownLatch countDownLatch,String id)
            this.quotaInfoVo=quotaInfoVo;
            this.countDownLatch=countDownLatch;
            this.id=id;
        
        @Override
        public void run() 
			//这里写自己的逻辑处理
			//处理完了记得countDown
            countDownLatch.countDown();
        
    

注意事项

最主要需要注意的就是主线程的这个部分:

try 
            //主线程等待所有统计指标执行完毕
            latch.await(5, TimeUnit.SECONDS);
            //latch.await();
            sw.stop();
            log.info("getQuotaInfo finish ,total time is ",sw.getTotalTimeMillis());
         catch (InterruptedException e) 
            e.printStackTrace();
        

latch.await如果不加等待时间的话,当某个线程执行出错,卡在那里,那么主线程会一直等待,这肯定是我们不想看到的,所以await一定要加等待时间。

以上是关于自定义线程池+countdownlatch的主要内容,如果未能解决你的问题,请参考以下文章

线程池和CountDownLatch配合使用,大数据量批量多次处理

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch(使用CountdownLatch原理改进: 配合线程池使用)

countdownlatch 导致的多线程死锁

172SpringBoot2的一个利用CountDownLatch和线程池优化查询接口执行效率的例子

172SpringBoot2的一个利用CountDownLatch和线程池优化查询接口执行效率的例子

SpringBoot自定义异步任务线程池