ThreadPoolExecutor-2

139 阅读4分钟

「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」。

4、工作线程如何从队列中获得任务

线程从任务队列中获取任务然后执行,执行完任务的空闲线程会再次去从队列中申请任务再去执行。这部分策略由getTask方法实现,其执行流程如下图所示: 122.png getTask这部分进行了多次判断,为的是控制线程的数量,使其符合线程池的状态。工作线程Worker会不断接收新任务去执行,而当工作线程Worker接收不到任务的时候,则会返回null值,表示线程池现在不应该持有那么多线程,在runWorker方法中就会调用processWorkerExit方法进行线程回收。遇到下列情况,worker必须退出:

  • 由于调用setMaximumPoolSize,worker数量超过了maximumPoolSize;
  • 线程池已经停止;
  • 线程池被shutdown且队列为空;
  • worker等待任务超时,要被销毁 下面是代码分析:
private Runnable getTask() {
    // 上一个poll调用是否超时标记
    boolean timedOut = false;
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
	// SHUTDOWN时会继续处理队列任务,如果队列为空,则需要销毁线程
	// STOP及以后状态,不允许处理队列中任务,也需要销毁线程
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
	    // 返回null,表示要销毁线程
            return null;
        }
			
	// 获取线程数量
        int wc = workerCountOf(c);
	// allowCoreThreadTimeOut默认为false,使核心线程即使空闲也保持活跃,如果为true,核心线程使用keepAliveTime参数来超时等待任务
	// 1.1 worker数量小于等于corePoolSize,timed为false
	// 2.1 worker数量大于corePoolSize,timed为true
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
			
	// 1.2 worker数量小于等于corePoolSize,则一定小于maximumPoolSize,跳过执行以下逻辑
	// 2.2 worker数量大于maximumPoolSize,则一定大于corePoolSize,timed为true,条件(wc > maximumPoolSize || (timed && timedOut))成立;
	// maxmumPoolSize最小值可设置为1,条件(wc > 1 || workQueue.isEmpty())也成立,所以返回null,表示要销毁当前worker
        if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
	    // 1.3 timed为false,执行workQueue.take(),阻塞等待,直到获取元素
	    // 2.3 timed为true,等待keepAliveTime时间后返回,r为null即队列此时为空,线程处于空闲状态,timedOut为true,再次循环,执行到2.2处就会返回null,表示销毁当前线程
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

5、如何销毁Worker?

Worker线程的run方法内部调用runWorker方法,内部有一个while循环,循环条件成立时,run方法无法退出,就能保证Worker一直活跃;while循环条件被打破,run方法就会退出,执行完run方法,线程就要走向死亡。在run方法快要结束时,调用processWorkerExit方法进行一些清理工作,主要内容包括:

  • 把自己从工人集合中移除;
  • 可能尝试终结线程池;
  • 如果少于corePoolSize的工人在运行,或者当前工人由于用户的代码异常而退出,或者队列非空但是没有工人,都会生成一个工人替换当前工人;
/**
 * 该方法由工作者线程调用
 *
 * @param w the worker
 * @param completedAbruptly worker是否由于用户代码的异常而死亡
 */
private void processWorkerExit(Worker w, boolean completedAbruptly) {
    // 用户代码异常,completedAbruptly为true 
    if (completedAbruptly)
        // 减少工人数量
        decrementWorkerCount();
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
	// 完成任务计数器,只在工人线程终结的时候修改
        completedTaskCount += w.completedTasks;
	// 从HashSet中移除
        workers.remove(w);
   } finally {
        mainLock.unlock();
    }
		
    // 尝试终结线程池
    tryTerminate();
		
    // 1、因为用户异常导致worker终结,新增worker;
    // 2、RUNNING或者SHUTDOWN状态,低于corePoolSize的worker在运行或者队列非空工人为0,新增worker
    int c = ctl.get();
    if (runStateLessThan(c, STOP)) {
        if (!completedAbruptly) {
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
           if (min == 0 && ! workQueue.isEmpty())
                min = 1;
            if (workerCountOf(c) >= min)
                return; // replacement not needed
        }
        addWorker(null, false);
    }
}

	
final void tryTerminate() {
    for (;;) {
        int c = ctl.get();
        // 正在运行,不能终结;
	// TIDYING状态,worker已全部被终结,不用终结;
	// SHUTDOWN状态,队列不为空,还有任务要处理,不能终结;
        if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        if (workerCountOf(c) != 0) {
	    // 中断至多一个空闲(等待任务)的线程
            interruptIdleWorkers(ONLY_ONE);
            return;
        }

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
	    // 设置线程池状态为TIDYING,worker数量为0
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
		    // 子类实现的方法
                    terminated();
                } finally {
		    // 线程池状态设置为TERMINATED,worker数量置为0
                    ctl.set(ctlOf(TERMINATED, 0));
                    // 唤醒因调用awaitTermination方法而阻塞的线程
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // 设置失败时,循环重试
    }
}