共计 1529 个字符,预计需要花费 4 分钟才能阅读完成。
线程池流程图
execute 外围办法
这里不必多说,其实就是线程池的流程图中的所说的,如果小于外围线程数量,创立外围线程,否则往队列仍工作,假如队列也满了,那就创立非核心线程,如果大于了 maximumPooSize,也就是说非核心线程也创立不了了,不好意思,那就走 reject 策略
addWorker
addWorker 别看代码比拟多,其实外围代码就是通过 CAS 来减少一个 Worker count 数,而后跳出循环,创立 Worker 加锁的形式退出到线程池中 workers(HashSet)数据结构中,而后启动 Worker
Worker
ThreadPoolExecutor 创立了一个 Worker 并启动了他,咱们是不是要看一下 Worker 是什么玩意?
唉吆喂,Worker 居然继承了 AQS 并实现了 Runnable,加锁的线程,是不是?好吧,那既然是线程了,那看一下他 run 办法吧:
首先看看一下 task != null || (task = getTask()) != null,这个条件,对于第一次创立外围线程并执行 run 来说,firstTask 是通过 w = new Worker(firstTask)传递过去,给了 Worker 实例变量了,所以 task 必定是不为 null 的,批准吧?
而后看外围代码 task.run,其实就是调用用户本人定义的 run 办法的逻辑,了解了吧
好了,那比如说咱们外围线程的第一个工作运行完了呢?那 getTask()就上场了:
其实有三局部外围逻辑 :
敞开线程池
如果曾经对线程池进行了 shutdown 了,那好,等我 workerQueue 队列工作生产结束,那我就线程退出
如果曾经对线程池进行了 stop,我去,好吧,你太暴力了,那就间接退出吧,会在 shutdownNow 中具体说
非核心线程超时
如果 wc > corePoolSize,也就是说有非核心线程,是不是 timed 为 true,而后非核心线程是以 workQueue.poll 以规定工夫来获取工作,此时如果工作是 null,没有工作,是不是 timedOut=true 了,好,而后再循环 timed 和 timedOut 都为 true 了,上述第二个逻辑的 if 就成立了,那非核心线程的 Worker 就会退出
阻塞和非阻塞形式获取工作
如果是外围线程,就会阻塞的形式 take 来拿工作,如果是非核心线程,就会进行 poll(time)形式来拿工作
shutdonwNow & shutdown
shutdonwNow
advanceRunState(STOP):将线程池的状态扭转为 STOP,实质上是一个线程标记位的扭转
interruptWorkers():对线程池中的所有线程都进行终止(interrupt) 操作这里会对所有的线程都会进行 interrupt,那当初就有一个疑难,Worker 会在哪里阻塞呢?其实有两处(Worker 中):
- 对于闲暇的线程会在 getTask 中以 take 阻塞的形式来拿工作
- 还有就是在 task.run 中,咱们本人定义业务逻辑如果有可中断的代码,就会被中断
而 shutdownNow 会对所有的 Worker 进行 interrupt,也可能会对正在运行的工作,如果能够响应中断,就会中断以后正在运行的工作,否则会进行下一次 getTask 的时候,即运行完当前任务,再下一次获取工作前判断退出 Worker 线程
- shutdown
interruptIdleWorkers:是 interrupt 闲暇的线程,谁是闲暇的线程?怎么来辨别,这里 AQS 就出场了
w.tryLock()是一个很要害的玩意,要晓得,如果 Worker 正在执行工作,正在执行 task.run(),这后面必定是加锁的,所以 tryLock 是拿不到锁的,所以针对正在运行的 Worker 线程是不 interrupt 的