关于线程池:再说Java线程池

4次阅读

共计 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 的

正文完
 0