Java-多线程之线程池是否需要关闭

Jmeter压力测试

背景

之前的文章Java—多线程之学了就要用-CountDownLatch中,用线程池处理相关业务的功能代码,在程序处理完毕后,线程池并未关闭,后来review代码的时候发现了这个问题,将线程池关闭。

上线之前通过jmeter进行压力测试。对比线程池关闭和不关闭时压力测试的情况。下面通过测试数据进行对比。

测试

  • 核心代码
@RestController
@RequestMapping("tbgl/tbjd")
public class TbjdController {
/**
     * 查询当前用户所有报表的填报进度情况
     * @param params
     * @return
     */
    @RequestMapping("/getRepProgress")
    public Map<String,Object> getRepProgress(@RequestParam Map<String, Object> params) {
        Map<String,Object> map = tbjdService.getRepProgress();
        map.put("code", 0);
        return map;
    }
}



@Service("tbjdService")
public class TbjdServiceImpl implements TbjdService {
    public Map<String,Object> getRepProgress(){
        final int PROCESSORS = Runtime.getRuntime().availableProcessors();
        Map<String,Object> tjMap = new HashMap<String,Object>(16);
        List<Map<String,Object>> progressList  = Collections.synchronizedList(new ArrayList<Map<String,Object>>());
       
        List<Map<String,Object>> distList = reportDao.getDistRecordList();

        AtomicInteger finishedNum = new AtomicInteger(0);
        AtomicInteger unfinishedNum =  new AtomicInteger(0);
        AtomicInteger notStartedNum =  new AtomicInteger(0);
        CountDownLatch latch = new CountDownLatch(distList.size());

        int corePoolSize = distList.size() < PROCESSORS ? distList.size():PROCESSORS;

        ExecutorService pool = new ThreadPoolExecutor(corePoolSize*2, PROCESSORS*8,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(1024), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

        for (Map<String,Object> map:distList) {
            pool.execute(() -> {
                // ....业务代码

                // 填报单位总数
                long sum = 0;
                // 已上报单位数
                long ysbSl = 0;
      
                String status = "";
                if(ysbSl == 0){
                    // 未开始
                    status = "01";
                    notStartedNum.incrementAndGet();
                }else if(ysbSl == sum){
                    // 已完成
                    status = "03";
                    finishedNum.incrementAndGet();
                }else{
                    // 进行中
                    status = "02";
                    unfinishedNum.incrementAndGet();
                }
                Map<String,Object> progressMap = new HashMap<String,Object>(16);                
                progressMap.put("status",status);
                progressMap.put("sbqk",ysbSl+"/"+sum);
                progressMap.put("progress",Math.round((float) ysbSl/(float)sum*100));

                progressList.add(progressMap);
                latch.countDown();
            });
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 关闭线程池
        pool.shutdown();
        System.out.println("计算任务处理完毕");

        tjMap.put("reportNum",distList.size());
        tjMap.put("unfinishedNum",unfinishedNum);
        tjMap.put("finishedNum",finishedNum);
        tjMap.put("notStartedNum",notStartedNum);
        tjMap.put("progressList",progressList);
        return tjMap;
    }
}
  • 测试任务

100个线程,运行5分钟

  • 运行结果

服务器配置

(1)未关闭线程池

87.7%的异常率,平均响应时间14757ms

创建线程数29478,峰值29372,线程全部处于驻留状态,运行了一段时间后,tomcat直接异常退出了

 

(2)关闭线程池(pool.shutdown())

异常率0.02%,平均响应时间2308ms

创建线程数216899,峰值1041,活动60

由压测结果可见,线程池在使用完毕后需要及时关闭,否则不能及时释放,导致在大量并发情况下,系统资源耗尽,程序异常退出


版权声明:本文为m0_37617778原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。