线程池ThreadPoolExecutor如何进行线程管理

概要

ThreadPoolExecutor作为java的线程管理对象,它如何管理线程,线程何时被创建,复用,退出

分析流程

public void execute(Runnable command) {
        if (command == null) {
           throw new NullPointerException();
        }
           
        int c = ctl.get();
        //当工作线程数小于设置的核心线程数时调用addWorker方法添加线程任务
        if (workerCountOf(c) < corePoolSize) {
        	//这里的ture代表是使用核心线程来创建运行此任务
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //当工作线程数大于设置的核心线程数时且线程池是运行状态,调用offer方法让任务入队列
        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);
        }
        //当队列满的时候 再尝试调用addWorker方法添加线程任务,直到达到最大线程数 这里的false代表是使用非核心线程来创建运行此任务
        else if (!addWorker(command, false))
            reject(command);
    }

上面是线程池任务提交的源码,从源码我们可以看到线程池执行的大概逻辑,但是对于线程的使用细节被隐藏在了addWorker方法,所以接着分析addWorker方法。

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                //工作线程数大于corePoolSize 或者 maximumPoolSize则提交任务被拒绝 取决于调用addWorker时传入的core
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

		//前面校验通过 可以创建一个新的线程执行当前提交的任务
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
        	//WorkerWorker类是重点 w.thread获取的线程来自于创建线程池对象传入的线程工厂类创建 
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                	//本身WorkerWorker也实现了Runnabale接口 这里的start方法会异步运行WorkerWorker的run方法 因为构造方法中传入此线程的任务是Worker自己(this)
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

addWorker方法逻辑主要两个部分,前面两个for循环是为了判断当前任务是否能创建一个线程来执行此任务,当线程池数量达到核心线程数或者最大线程数(要看前面的提交方式),那么不会再创建新的线程执行该任务。当校验完可以创建新的线程执行任务时,会创建一个Worker对象进行包装,firstTask就是我们提交的原始的Runnable任务,不过Worker对象本身实现了Runnable接口,并且在线程中传入的是Worker,所以运行t.start()实际是调用Workerrun方法

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            //这里已经开始创建线程了 getThreadFactory就是来自于创建线程池对象传入的线程工厂类  
            this.thread = getThreadFactory().newThread(this);
        }
      }

Worker构造方法如上,Worker类持有我们提交的任务firstTask,并且把自己作为Runnable传入到线程中,所以当前线程start方法就调用的是Workerrun方法。
注意:这里已经开始创建线程了

	public void run() {
            runWorker(this);
        }
        
    //此方法才是核心
   	final void runWorker(Worker w) {
   		//获取到当前线程 当前线程就是上层通过线程工厂类创建的线程
        Thread wt = Thread.currentThread();
        //把Worker自己持有的任务firstTask赋值给task
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
        	//开启循环执行任务 当task不为null 或者getTask不为null时 不断的执行我们提交的任务 getTask的任务来源就是从队列workQueue中获取的 当跳出这个while循环此线程相当于线程退出(销毁)
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                    	//真正的运行我们提交的任务
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                	//执行完任务赋值为null  第一次之后的while循环就走task = getTask()判断
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

看到这里,大致流程已经豁然开朗。当通过调用addWorker方法运行的任务,会在Worker.runWorker方法中开启while循环,当firstTask任务(调用addWorker一定会传过来)执行完之后,·task != null·会恒等于false,此时(task = getTask()) != null就会从队列里面获取任务来执行。由于workQueue是一个阻塞队列,当队列没有任务的时候,它会阻塞直至我们设置的超时时间超时,这就是线程最大空闲时间的会被销毁的原因(跳出while循环,线程退出),为什么要用阻塞队列相信你也get到了。
值得注意的是:默认情况下,只有非核心线程会销毁

  private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?
		//循环拉取队列中的任务 
		//如果当前工作线程数大于核心线程数 拉取不到则返回null 
		//如果工作线程数不大于核心线程数 就算超时也会去循环拉取 
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //线程池状态是STOP状态及以上 返回null 如果是SHUTDOWN状态 那么需要把队列先排干
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            //allowCoreThreadTimeOut 默认核心线程不退出 判断的是数量 不是指的某些线程一定就是核心线程
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
              	//超时退出 返回null
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
            	//poll keepAliveTime 超时则返回null keepAliveTime是创建线程池时设置的超时时间
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

值得注意的是:如果线程池状态是STOP状态及以上,则当前线程直接退出。如果是SHUTDOWN状态,那么需要把队列先排干再退出。如果线程池正常运行,默认情况下,如果当前工作线程数大于核心线程数,拉取不到则返回null,否则就算超时也会去循环拉取,返回null会导致线程被销毁

总结

1、当线程池工作线程数没有达到核心线程数时,则调用addWorker创建一个线程执行该任务(创建阶段)
2、当核心线程数满了且队列已满的情况下调用addWorker创建一个线程该任务,直到线程达到最大线程数为止 (创建阶段)
3、通过addWorker创建的线程会开启while循环让线程复用,线程的任务从队列里面获取 (复用阶段)
4、从队列里面获取任务超时且当线工作程数大于核心线程数时,则当前线程退出 (销毁阶段)
5、如果线程池状态是STOP状态及以上,则当前线程直接退出。如果是SHUTDOWN状态,那么需要把队列先排干再退出 (销毁阶段)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值