Skip to content

Commit 9276ac2

Browse files
authored
Merge pull request #2574 from 1020325258/12-29
核心线程空闲时处于什么状态
2 parents d11cfa5 + e457037 commit 9276ac2

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

docs/java/concurrent/java-concurrent-questions-03.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,65 @@ public void allowCoreThreadTimeOut(boolean value) {
361361
}
362362
```
363363

364+
### 核心线程空闲时处于什么状态?
365+
366+
核心线程空闲时,其状态分为以下两种情况:
367+
368+
- **设置了核心线程的存活时间** :核心线程在空闲时,会处于 `WAITING` 状态,等待获取任务。如果阻塞等待的时间超过了核心线程存活时间,则该线程会退出工作,将该线程从线程池的工作线程集合中移除,线程状态变为 `TERMINATED` 状态。
369+
- **没有设置核心线程的存活时间** :核心线程在空闲时,会一直处于 `WAITING` 状态,等待获取任务,核心线程会一直存活在线程池中。
370+
371+
当队列中有可用任务时,会唤醒被阻塞的线程,线程的状态会由 `WAITING` 状态变为 `RUNNABLE` 状态,之后去执行对应任务。
372+
373+
#### 相关源码
374+
375+
接下来通过相关源码,了解一下线程池内部是如何做的。
376+
377+
线程在线程池内部被抽象为了 `Worker` ,当 `Worker` 被启动之后,会不断去任务队列中获取任务。
378+
379+
在获取任务的时候,会根据 `timed` 值来决定从任务队列( `BlockingQueue` )获取任务的行为。
380+
381+
如果「设置了核心线程的存活时间」或者「线程数量超过了核心线程数量」,则将 `timed` 标记为 `true` ,表明获取任务时需要使用 `poll()` 指定超时时间。
382+
383+
- `timed == true` :使用 `poll()` 来获取任务。使用 `poll()` 方法获取任务超时的话,则当前线程会退出执行( `TERMINATED` ),该线程从线程池中被移除。
384+
- `timed == false` :使用 `take()` 来获取任务。使用 `take()` 方法获取任务会让当前线程一直阻塞等待(`WAITING`)。
385+
386+
源码如下:
387+
388+
```JAVA
389+
// ThreadPoolExecutor
390+
private Runnable getTask() {
391+
boolean timedOut = false;
392+
for (;;) {
393+
// ...
394+
395+
// 1、如果「设置了核心线程的存活时间」或者是「线程数量超过了核心线程数量」,则 timed 为 true。
396+
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
397+
// 2、扣减线程数量。
398+
// wc > maximuimPoolSize:线程池中的线程数量超过最大线程数量。其中 wc 为线程池中的线程数量。
399+
// timed && timeOut:timeOut 表示获取任务超时。
400+
// 分为两种情况:核心线程设置了存活时间 && 获取任务超时,则扣减线程数量;线程数量超过了核心线程数量 && 获取任务超时,则扣减线程数量。
401+
if ((wc > maximumPoolSize || (timed && timedOut))
402+
&& (wc > 1 || workQueue.isEmpty())) {
403+
if (compareAndDecrementWorkerCount(c))
404+
return null;
405+
continue;
406+
}
407+
try {
408+
// 3、如果 timed 为 true,则使用 poll() 获取任务;否则,使用 take() 获取任务。
409+
Runnable r = timed ?
410+
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
411+
workQueue.take();
412+
// 4、获取任务之后返回。
413+
if (r != null)
414+
return r;
415+
timedOut = true;
416+
} catch (InterruptedException retry) {
417+
timedOut = false;
418+
}
419+
}
420+
}
421+
```
422+
364423
### ⭐️线程池的拒绝策略有哪些?
365424

366425
如果当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时,`ThreadPoolExecutor` 定义一些策略:

0 commit comments

Comments
 (0)