深入理解Java线程池ThreadPoolExecutor

1:先看下线程池属性配置

public ThreadPoolExecutor(int corePoolSize,    //核心线程池个数
                          int maximumPoolSize, //最大线程池个数
                          long keepAliveTime, //非核心线程存活时间
                          TimeUnit unit,      //时间格式
                          BlockingQueue<Runnable> workQueue,  //存放Runnable的工作队列
                          ThreadFactory threadFactory,      //创建线程所需工厂
                          RejectedExecutionHandler handler //超出workQueue最大等待队列与maximumPoolSize之和会回调此接口) 
  

1:corePoolSize(核心线程池个数)核心线程会一直存在,并且一直运行,知道关闭线程池或者线程被中断。

2:maximumPoolSize(最大线程池个数)就是该线程池允许创建线程的最大个数。

3:unit(时间格式)时,分,秒等。

4:workQueue(存放Runnable的工作队列)

(1)当corePoolSize为5,workQueue的长度为5,则同时创建5个核心线程取执行这5个工作队列。也就是说workQueue的长度小于等于corePoolSize时会创建workQueue长度的线程取执行工作队列(我使用JDK1.8是这样的,1.6的不确定)。

(2)当工作队列workQueue的size大于核心线程池数并且小于阻塞队列的个数(用ArrayBlockingQueue可以设置等待队列的个数),则只会创建全部的核心线程取执行工作队列里的数据,其他队列处于阻塞状态。

(3)当工作队列workQueue的size大于核心线程池数并且大于等待队列的个数,则会新建线程执行队列。新建线程个数=工作队列个数 - 核心线程池数 - 阻塞队列数。

(3)当工作队列workQueue的size > (maximumPoolSize+工作队阻塞待个数)  会回调 handler 将超出的队列抛出。需要在回调处将队列重新加到线程池里,否则该队里的功能将不再执行。此时回调与执行execute在同一个线程,若是主线程,队列一直处于超出状态,主线程会卡死。

2:内部执行原理

(1)调用执行方法

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) { //小于核心线程个数
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {   // 大于核心线程数量,核心线程开启失败,并且阻塞队列未满
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))  // 当工作队列workQueue的size > (maximumPoolSize+工作队列阻塞个数)
            reject(command);
    }

(2)addWorker方法

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
/**
走出该死循环并继续执行该方法之后代码条件是:小于核心线程数或者大于核心线程数与阻塞数之和,或者核心线程未开启
*/
        for (;;) {
           ……  //代码省略
        }
……
        try {
            w = new Worker(firstTask);      //创建线程,将该工作任务绑定到该线程
            final Thread t = w.thread;
            if (t != null) {
              ……
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);                                                  //将创建的线程存入线程队列里
                      ……                  

  }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();                             //开启线程
                    workerStarted = true;
                }
            }
        } …….
        return workerStarted;
    }

 

(3)Worker 类

Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);       //创建线程
}

(4)当线程启动时会执行Worker 类中的run方法

public void run() {
    runWorker(this); //继续跟踪该方法
}

(5)runWorker方法

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {

//首先执行该线程绑定的任务。而getTask()方法是有关核心线程如何回收重用的,
            while (task != null || (task = getTask()) != null) {   
             ……
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

(6)getTask()方法

private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?
//该循环是死循环,当为核心线程时,队列为空,则一直循环,不为空则返回给runWorker(Worker w) 中的while循环,当非核心线程,则存活到keepAliveTime时间,会跳出该循环,同时也满足退出runWorker(Worker w) 中的while循环,所以该线程结束生命周期。
        for (;;) {
       ……
            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :        //当为非核心线程,执行该代码
                    workQueue.take();     //当为核心线程执行该行。一直从队列拿数据,所以外面只要往线程池加队列,就会立马执行。所以核心线程一直死循环存在。解释了核心线程为什么能够被重新利用                                           
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值