问题描述
我正在经历 Java Concurrency In Practice ,并坚持 8.3.1线程创建和拆解主题。以下脚注警告将 corePoolSize
保持为零。
I was going through Java Concurrency In Practice and got stuck at the 8.3.1 Thread creation and teardown topic. The following footnote warns about keeping corePoolSize
to zero.
所以为了验证这一点,我编写了这个程序,如上所述。
So to verify this I wrote this program which does not work as stated above.
final int corePoolSize = 0;
ThreadPoolExecutor tp = new ThreadPoolExecutor(corePoolSize, 1, 5, TimeUnit.SECONDS,
new LinkedBlockingQueue<>());
// If the pool is already at the core size
if (tp.getPoolSize() == corePoolSize) {
ExecutorService ex = tp;
// So tasks submitted to a thread pool with a work queue that has any capacity
// and a core size of zero will not execute until the queue fills up.
// So, this should not execute until queue fills up.
ex.execute(() -> System.out.println("Hello"));
}
输出:
你好
那么,程序的行为是否表明 ThreadPoolExecutor
创建至少一个线程无论 corePoolSize = 0
,都会提交任务。如果是,那么教科书中的警告是什么。
So, does the behavior of the program suggest that ThreadPoolExecutor
creates at least one thread if a task is submitted irrespective of corePoolSize=0
. If yes, then what is the warning about in the text book.
编辑:测试 jdk1.5.0_22 on @ SK的建议如下:
Tested the code in jdk1.5.0_22 upon @S.K.'s suggestion with following change:
ThreadPoolExecutor tp = new ThreadPoolExecutor(corePoolSize, 1, 5, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(1));//Queue size is set to 1.
但是有了这个改变,程序终止而不打印任何输出。
所以我误解了这些陈述来自这本书?
编辑(@sjlee):在评论中添加代码很难,所以我会添加它在这里编辑...你可以尝试这个修改并针对最新的JDK和JDK 1.5运行吗?
EDIT (@sjlee): It's hard to add code in the comment, so I'll add it as an edit here... Can you try out this modification and run it against both the latest JDK and JDK 1.5?
final int corePoolSize = 0;
ThreadPoolExecutor tp = new ThreadPoolExecutor(corePoolSize, 1, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
// If the pool is already at the core size
if (tp.getPoolSize() == corePoolSize) {
ExecutorService ex = tp;
// So tasks submitted to a thread pool with a work queue that has any capacity
// and a core size of zero will not execute until the queue fills up.
// So, this should not execute until queue fills up.
ex.execute(() -> System.out.println("Hello"));
}
tp.shutdown();
if (tp.awaitTermination(1, TimeUnit.SECONDS)) {
System.out.println("thread pool shut down. exiting.");
} else {
System.out.println("shutdown timed out. exiting.");
}
推荐答案
在jdk中运行此程序时1.5,1.6,1.7和1.8,我在1.5,1.6和1.7+中发现了 ThreadPoolExecutor#execute(Runnable)
的不同实现。这是我发现的:
While running this program in jdk 1.5,1.6,1.7 and 1.8, I found different implementations of ThreadPoolExecutor#execute(Runnable)
in 1.5,1.6 and 1.7+. Here's what I found:
JDK 1.5实施
//Here poolSize is the number of core threads running.
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
for (;;) {
if (runState != RUNNING) {
reject(command);
return;
}
if (poolSize < corePoolSize && addIfUnderCorePoolSize(command))
return;
if (workQueue.offer(command))
return;
Runnable r = addIfUnderMaximumPoolSize(command);
if (r == command)
return;
if (r == null) {
reject(command);
return;
}
// else retry
}
}
当 corePoolSize
为0时,此实现不会创建线程,因此提供的任务不会执行。
This implementation does not create a thread when corePoolSize
is 0, therefore the supplied task does not execute.
JDK 1.6实施
//Here poolSize is the number of core threads running.
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
}
else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
}
}
JDK 1.6即使 corePoolSize
为0,也会创建一个新线程。
JDK 1.6 creates a new thread even if the corePoolSize
is 0.
JDK 1.7+实施(类似于JDK 1.6但具有更好的锁定和状态检查)
JDK 1.7+ implementation(Similar to JDK 1.6 but with better locks and state checks)
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
即使<$ c,JDK 1.7也会创建一个新线程$ c> corePoolSize 为0。
JDK 1.7 too creates a new thread even if the corePoolSize
is 0.
所以,似乎 corePoolSize = 0
是JDK 1.5和JDK 1.6+的每个版本的特例。
So, it seems that corePoolSize=0
is a special case in each versions of JDK 1.5 and JDK 1.6+.
但奇怪的是,该书的解释与任何节目结果都不符。
这篇关于具有corePoolSize 0的ThreadPoolExecutor在任务队列已满之前不应执行任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!