From 4d833d31bd48edc2fcfa55e935401007086f6267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?11=E6=9D=A5=E4=BA=86?= Date: Sun, 29 Dec 2024 19:45:43 +0800 Subject: [PATCH 1/5] =?UTF-8?q?[docs=20update]=E6=A0=B8=E5=BF=83=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E7=A9=BA=E9=97=B2=E6=97=B6=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java-concurrent-questions-03.md | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/docs/java/concurrent/java-concurrent-questions-03.md b/docs/java/concurrent/java-concurrent-questions-03.md index 96eb282c..f9334ed8 100644 --- a/docs/java/concurrent/java-concurrent-questions-03.md +++ b/docs/java/concurrent/java-concurrent-questions-03.md @@ -361,6 +361,67 @@ public void allowCoreThreadTimeOut(boolean value) { } ``` +### 核心线程空闲时处于什么状态? + +核心线程空闲时,其状态分为以下两种情况: + +- **设置了核心线程的存活时间** :核心线程在空闲时,会处于阻塞状态,等待获取任务。如果阻塞等待的时间超过了核心线程存活时间,则该核心线程会被销毁。 +- **没有设置核心线程的存活时间** :核心线程在空闲时,会一直处于阻塞状态,等待获取任务。 + +#### 相关源码 + +接下来通过相关源码,了解一下线程池内部是如何做的。 + +线程在线程池内部被抽象为了 `Worker` ,当 `Worker` 被启动之后,会不断去任务队列中获取任务。 + +在获取任务的时候,会根据 `timed` 值来决定从任务队列( `BlockingQueue` )获取任务的行为。 + +如果「设置了核心线程的存活时间」或者「线程数量超过了核心线程数量」,则将 `timed` 标记为 `true` : + +- `timed == true` :使用 `poll()` 来获取任务。`poll()` 方法会指定获取任务的等待时间,如果到达等待时间之后,还没有获取到任务,则会返回 `null`。 +- `timed == false` :使用 `take()` 来获取任务。`take()` 方法是 `BlockingQueue` 中的阻塞方法,调用之后,线程会进入等待状态,直到从队列中获取任务。 + +因此,如果「设置了核心线程的存活时间」,核心线程没有在超时时间之内获取到任务,则会被销毁。 + +如果「没有设置核心线程的存活时间」,则核心线程在没有获取到任务时,会通过 `take()` 方法进行阻塞等待。 + +源码如下: + +```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` 定义一些策略: From d6eca60aadc7def1b7aa4aad41ef17280846bb60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?11=E6=9D=A5=E4=BA=86?= Date: Sun, 29 Dec 2024 21:00:31 +0800 Subject: [PATCH 2/5] =?UTF-8?q?[docs=20update]=E6=A0=B8=E5=BF=83=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E7=A9=BA=E9=97=B2=E6=97=B6=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/java/concurrent/java-concurrent-questions-03.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/java/concurrent/java-concurrent-questions-03.md b/docs/java/concurrent/java-concurrent-questions-03.md index f9334ed8..9d2317ea 100644 --- a/docs/java/concurrent/java-concurrent-questions-03.md +++ b/docs/java/concurrent/java-concurrent-questions-03.md @@ -365,7 +365,7 @@ public void allowCoreThreadTimeOut(boolean value) { 核心线程空闲时,其状态分为以下两种情况: -- **设置了核心线程的存活时间** :核心线程在空闲时,会处于阻塞状态,等待获取任务。如果阻塞等待的时间超过了核心线程存活时间,则该核心线程会被销毁。 +- **设置了核心线程的存活时间** :核心线程在空闲时,会处于阻塞状态,等待获取任务。如果阻塞等待的时间超过了核心线程存活时间,则该线程会退出工作,之后将该线程从线程池的工作线程集合中移除。 - **没有设置核心线程的存活时间** :核心线程在空闲时,会一直处于阻塞状态,等待获取任务。 #### 相关源码 @@ -376,7 +376,7 @@ public void allowCoreThreadTimeOut(boolean value) { 在获取任务的时候,会根据 `timed` 值来决定从任务队列( `BlockingQueue` )获取任务的行为。 -如果「设置了核心线程的存活时间」或者「线程数量超过了核心线程数量」,则将 `timed` 标记为 `true` : +如果「设置了核心线程的存活时间」或者「线程数量超过了核心线程数量」,则将 `timed` 标记为 `true` ,表明获取任务时需要使用 `poll()` 指定超时时间,如果获取超时,则当前线程线程会退出线程池。 - `timed == true` :使用 `poll()` 来获取任务。`poll()` 方法会指定获取任务的等待时间,如果到达等待时间之后,还没有获取到任务,则会返回 `null`。 - `timed == false` :使用 `take()` 来获取任务。`take()` 方法是 `BlockingQueue` 中的阻塞方法,调用之后,线程会进入等待状态,直到从队列中获取任务。 From 330d1dc596349d4157a7472412212ef4e81e0d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?11=E6=9D=A5=E4=BA=86?= Date: Sun, 29 Dec 2024 22:01:17 +0800 Subject: [PATCH 3/5] =?UTF-8?q?[docs=20update]=E5=A2=9E=E5=8A=A0=E7=8A=B6?= =?UTF-8?q?=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/java/concurrent/java-concurrent-questions-03.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/java/concurrent/java-concurrent-questions-03.md b/docs/java/concurrent/java-concurrent-questions-03.md index 9d2317ea..ffb4f721 100644 --- a/docs/java/concurrent/java-concurrent-questions-03.md +++ b/docs/java/concurrent/java-concurrent-questions-03.md @@ -365,8 +365,10 @@ public void allowCoreThreadTimeOut(boolean value) { 核心线程空闲时,其状态分为以下两种情况: -- **设置了核心线程的存活时间** :核心线程在空闲时,会处于阻塞状态,等待获取任务。如果阻塞等待的时间超过了核心线程存活时间,则该线程会退出工作,之后将该线程从线程池的工作线程集合中移除。 -- **没有设置核心线程的存活时间** :核心线程在空闲时,会一直处于阻塞状态,等待获取任务。 +- **设置了核心线程的存活时间** :核心线程在空闲时,会处于 `WAITING` 状态,等待获取任务。如果阻塞等待的时间超过了核心线程存活时间,则该线程会退出工作,将该线程从线程池的工作线程集合中移除,线程状态变为 `TERMINATED` 状态。 +- **没有设置核心线程的存活时间** :核心线程在空闲时,会处于 `WAITING` 状态,等待获取任务。 + +当核心线程获取任务之后,会由 `WAITING` 状态变为 `RUNNABLE` 状态,之后去执行对应任务。 #### 相关源码 From 01c961b9a17750725a1ac2290c30a182151fbb70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?11=E6=9D=A5=E4=BA=86?= Date: Sun, 29 Dec 2024 22:02:01 +0800 Subject: [PATCH 4/5] =?UTF-8?q?[docs=20update]=E5=AE=8C=E5=96=84=E6=96=87?= =?UTF-8?q?=E5=AD=97=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/java/concurrent/java-concurrent-questions-03.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/java/concurrent/java-concurrent-questions-03.md b/docs/java/concurrent/java-concurrent-questions-03.md index ffb4f721..0b2dab5c 100644 --- a/docs/java/concurrent/java-concurrent-questions-03.md +++ b/docs/java/concurrent/java-concurrent-questions-03.md @@ -366,7 +366,7 @@ public void allowCoreThreadTimeOut(boolean value) { 核心线程空闲时,其状态分为以下两种情况: - **设置了核心线程的存活时间** :核心线程在空闲时,会处于 `WAITING` 状态,等待获取任务。如果阻塞等待的时间超过了核心线程存活时间,则该线程会退出工作,将该线程从线程池的工作线程集合中移除,线程状态变为 `TERMINATED` 状态。 -- **没有设置核心线程的存活时间** :核心线程在空闲时,会处于 `WAITING` 状态,等待获取任务。 +- **没有设置核心线程的存活时间** :核心线程在空闲时,会一直处于 `WAITING` 状态,等待获取任务。 当核心线程获取任务之后,会由 `WAITING` 状态变为 `RUNNABLE` 状态,之后去执行对应任务。 From e457037f43053f4735fe114ac5b1cab55cb81915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?11=E6=9D=A5=E4=BA=86?= Date: Sun, 29 Dec 2024 22:11:58 +0800 Subject: [PATCH 5/5] =?UTF-8?q?[docs=20update]=E5=AE=8C=E5=96=84=E6=96=87?= =?UTF-8?q?=E5=AD=97=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../concurrent/java-concurrent-questions-03.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/docs/java/concurrent/java-concurrent-questions-03.md b/docs/java/concurrent/java-concurrent-questions-03.md index 0b2dab5c..6e376bbf 100644 --- a/docs/java/concurrent/java-concurrent-questions-03.md +++ b/docs/java/concurrent/java-concurrent-questions-03.md @@ -366,9 +366,9 @@ public void allowCoreThreadTimeOut(boolean value) { 核心线程空闲时,其状态分为以下两种情况: - **设置了核心线程的存活时间** :核心线程在空闲时,会处于 `WAITING` 状态,等待获取任务。如果阻塞等待的时间超过了核心线程存活时间,则该线程会退出工作,将该线程从线程池的工作线程集合中移除,线程状态变为 `TERMINATED` 状态。 -- **没有设置核心线程的存活时间** :核心线程在空闲时,会一直处于 `WAITING` 状态,等待获取任务。 +- **没有设置核心线程的存活时间** :核心线程在空闲时,会一直处于 `WAITING` 状态,等待获取任务,核心线程会一直存活在线程池中。 -当核心线程获取任务之后,会由 `WAITING` 状态变为 `RUNNABLE` 状态,之后去执行对应任务。 +当队列中有可用任务时,会唤醒被阻塞的线程,线程的状态会由 `WAITING` 状态变为 `RUNNABLE` 状态,之后去执行对应任务。 #### 相关源码 @@ -378,14 +378,10 @@ public void allowCoreThreadTimeOut(boolean value) { 在获取任务的时候,会根据 `timed` 值来决定从任务队列( `BlockingQueue` )获取任务的行为。 -如果「设置了核心线程的存活时间」或者「线程数量超过了核心线程数量」,则将 `timed` 标记为 `true` ,表明获取任务时需要使用 `poll()` 指定超时时间,如果获取超时,则当前线程线程会退出线程池。 +如果「设置了核心线程的存活时间」或者「线程数量超过了核心线程数量」,则将 `timed` 标记为 `true` ,表明获取任务时需要使用 `poll()` 指定超时时间。 -- `timed == true` :使用 `poll()` 来获取任务。`poll()` 方法会指定获取任务的等待时间,如果到达等待时间之后,还没有获取到任务,则会返回 `null`。 -- `timed == false` :使用 `take()` 来获取任务。`take()` 方法是 `BlockingQueue` 中的阻塞方法,调用之后,线程会进入等待状态,直到从队列中获取任务。 - -因此,如果「设置了核心线程的存活时间」,核心线程没有在超时时间之内获取到任务,则会被销毁。 - -如果「没有设置核心线程的存活时间」,则核心线程在没有获取到任务时,会通过 `take()` 方法进行阻塞等待。 +- `timed == true` :使用 `poll()` 来获取任务。使用 `poll()` 方法获取任务超时的话,则当前线程会退出执行( `TERMINATED` ),该线程从线程池中被移除。 +- `timed == false` :使用 `take()` 来获取任务。使用 `take()` 方法获取任务会让当前线程一直阻塞等待(`WAITING`)。 源码如下: