diff --git a/docs/java/concurrent/java-concurrent-questions-03.md b/docs/java/concurrent/java-concurrent-questions-03.md index 96eb282c..6e376bbf 100644 --- a/docs/java/concurrent/java-concurrent-questions-03.md +++ b/docs/java/concurrent/java-concurrent-questions-03.md @@ -361,6 +361,65 @@ public void allowCoreThreadTimeOut(boolean value) { } ``` +### 核心线程空闲时处于什么状态? + +核心线程空闲时,其状态分为以下两种情况: + +- **设置了核心线程的存活时间** :核心线程在空闲时,会处于 `WAITING` 状态,等待获取任务。如果阻塞等待的时间超过了核心线程存活时间,则该线程会退出工作,将该线程从线程池的工作线程集合中移除,线程状态变为 `TERMINATED` 状态。 +- **没有设置核心线程的存活时间** :核心线程在空闲时,会一直处于 `WAITING` 状态,等待获取任务,核心线程会一直存活在线程池中。 + +当队列中有可用任务时,会唤醒被阻塞的线程,线程的状态会由 `WAITING` 状态变为 `RUNNABLE` 状态,之后去执行对应任务。 + +#### 相关源码 + +接下来通过相关源码,了解一下线程池内部是如何做的。 + +线程在线程池内部被抽象为了 `Worker` ,当 `Worker` 被启动之后,会不断去任务队列中获取任务。 + +在获取任务的时候,会根据 `timed` 值来决定从任务队列( `BlockingQueue` )获取任务的行为。 + +如果「设置了核心线程的存活时间」或者「线程数量超过了核心线程数量」,则将 `timed` 标记为 `true` ,表明获取任务时需要使用 `poll()` 指定超时时间。 + +- `timed == true` :使用 `poll()` 来获取任务。使用 `poll()` 方法获取任务超时的话,则当前线程会退出执行( `TERMINATED` ),该线程从线程池中被移除。 +- `timed == false` :使用 `take()` 来获取任务。使用 `take()` 方法获取任务会让当前线程一直阻塞等待(`WAITING`)。 + +源码如下: + +```JAVA +// ThreadPoolExecutor +private Runnable getTask() { + boolean timedOut = false; + for (;;) { + // ... + + // 1、如果「设置了核心线程的存活时间」或者是「线程数量超过了核心线程数量」,则 timed 为 true。 + boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; + // 2、扣减线程数量。 + // wc > maximuimPoolSize:线程池中的线程数量超过最大线程数量。其中 wc 为线程池中的线程数量。 + // timed && timeOut:timeOut 表示获取任务超时。 + // 分为两种情况:核心线程设置了存活时间 && 获取任务超时,则扣减线程数量;线程数量超过了核心线程数量 && 获取任务超时,则扣减线程数量。 + if ((wc > maximumPoolSize || (timed && timedOut)) + && (wc > 1 || workQueue.isEmpty())) { + if (compareAndDecrementWorkerCount(c)) + return null; + continue; + } + try { + // 3、如果 timed 为 true,则使用 poll() 获取任务;否则,使用 take() 获取任务。 + Runnable r = timed ? + workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : + workQueue.take(); + // 4、获取任务之后返回。 + if (r != null) + return r; + timedOut = true; + } catch (InterruptedException retry) { + timedOut = false; + } + } +} +``` + ### ⭐️线程池的拒绝策略有哪些? 如果当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时,`ThreadPoolExecutor` 定义一些策略: