• java线程池ThreadPoolExecutor的keepAliveTime=0时,表示超过core线程数的线程在空闲时立即结束!!!


    今天同事突然提出问题说用哪个线程池好,newFixedThreadPool和newCacheThreadPool里选择,说固定大小线程池keepAliveTime=0,线程空闲会立马回收线程从而节约资源,然后另外一个同事说,0是代表永远不回收,我记忆里也是记得0是永久存活,因为网上很多博客啊,资料啊都是说的0表示线程永久存活在空闲的时候。前面那位同事也是从字面上认为的,没有经过验证,觉得-1才是永久不回收,然后各自进行了一波研究分析。

    经过看源码,发现keepAliveTime<0是不行的,直接报错,也就是同事的猜测-1才是不回收 是错误的,看下面代码图示(别问我怎么给代码里部分标红,直接用浏览器F12自己编辑页面写标签样式进去的。。)

    public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler) {
            if (corePoolSize < 0 ||
                maximumPoolSize <= 0 ||
                maximumPoolSize < corePoolSize ||
                keepAliveTime < 0)
                throw new IllegalArgumentException();
            if (workQueue == null || threadFactory == null || handler == null)
                throw new NullPointerException();
            this.acc = System.getSecurityManager() == null ?
                    null :
                    AccessController.getContext();
            this.corePoolSize = corePoolSize;
            this.maximumPoolSize = maximumPoolSize;
            this.workQueue = workQueue;
            this.keepAliveTime = unit.toNanos(keepAliveTime);
            this.threadFactory = threadFactory;
            this.handler = handler;
        }
    然后找keepAliveTime的使用一时半会也没找到,就用代码测试了,发现设置keepAliveTime=0核心线程数确实没有回收,后面同事说在并发病程的艺术那本书上有一段描述

    “当线程池中的线程数大于corePoolSize时,keepAliveTime为多余的空闲线程等待新任务的 最长时间,超过这个时间后多余的线程将被终止。这里把keepAliveTime设置为0L,意味着多余 的空闲线程会被立即终止。”

    同事又开始迷茫了,我一开始没细看,觉得说的不对,后面反复阅读,发现这段文字描述的是说keepAliveTime控制的是非核心线程数的回收,也就是0的时候,非核心线程数会在空闲的时候回收,并不是说核心的会回收。

    为了验证结果,我们就用代码进行了测试,测试代码如下:

    package com.xhs.concurrent.threaddemo.sync;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
     
    /**
     * @author xuhan  build  2019/4/23
     */
    public class ExecutorsDemo implements Runnable{
     
        private int i=0;
     
        public ExecutorsDemo(int i) {
            this.i = i;
        }
        public static void main(String[] args) {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1,2,0, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(1));
            for(int i=0;i<3;i++){
                executor.execute(new ExecutorsDemo(i));
            }
            while(true){
                System.out.println("总线程数:"+executor.getPoolSize()+"当前活跃线程数:"+executor.getActiveCount());
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        @Override
        public void run() {
            System.out.println("i="+i+" Thread = "+Thread.currentThread().getName());
            if(i>=1){
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("i="+i+" sleep 1 s结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else{
                try {
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println("i="+i+" sleep 3 s结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    设置核心线程数和非核心线程数分别为1个,队列容量为1,进入3个runnable:

    第一个创建主线程,第二个进入队列,第三个则创建非主线程运行,

    输出结果为

    i=0 Thread = pool-1-thread-1
    i=2 Thread = pool-1-thread-2
    总线程数:2当前活跃线程数:2
    总线程数:2当前活跃线程数:2
    i=2 sleep 1 s结束
    i=1 Thread = pool-1-thread-2
    总线程数:2当前活跃线程数:2
    总线程数:2当前活跃线程数:2
    i=1 sleep 1 s结束
    总线程数:1当前活跃线程数:1
    总线程数:1当前活跃线程数:1
    i=0 sleep 3 s结束
    总线程数:1当前活跃线程数:0
    可以看到非核心数线程执行完毕之后,队列中的task进入继续执行,等再次进入队列的task结束后,可以看到总线程数减少了1,而等核心线程执行完毕后,发现总线程数没有减少,但活跃线程数减少,也就是核心线程数没有回收。书上说的是正确的,大部分网上的博客说的keepAliveTime=0永久不回收是有出入的。

    如果要设置核心线程的回收,则需要设置

    executor.allowCoreThreadTimeOut(true);
    但这是keepAliveTime必须要>0才行,否则会抛出异常!!!

    throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
    如果看了之后觉得有问题,希望各位指点一番!!谢谢!!

  • 相关阅读:
    Windows 编程
    javascript 快速入门
    python 在windows下监听键盘按键
    eleme 项目使用到的库
    lftp 快速使用
    自动测试工具
    Cookie(1)
    fillder script使用
    Boost.Hana
    Haskell语言学习笔记(50)Extra
  • 原文地址:https://www.cnblogs.com/zhuyeshen/p/12171910.html
Copyright © 2020-2023  润新知