3 回答
TA贡献2012条经验 获得超12个赞
在 jdk 1.5、1.6、1.7 和 1.8 中运行这个程序时,我发现ThreadPoolExecutor#execute(Runnable)了 1.5、1.6 和 1.7+ 中的不同实现。这是我发现的:
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 时,此实现不会创建线程,因此不会执行提供的任务。
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
}
}
即使corePoolSize为 0,JDK 1.6 也会创建一个新线程。
JDK 1.7+ 实现(类似于 JDK 1.6,但具有更好的锁和状态检查)
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);
}
即使corePoolSize是 0,JDK 1.7 也会创建一个新线程。
因此,corePoolSize=0在 JDK 1.5 和 JDK 1.6+ 的每个版本中,这似乎都是一个特例。
但奇怪的是,书中的解释与任何程序结果都不符。
TA贡献1834条经验 获得超8个赞
似乎这是旧 Java 版本的错误,但现在在 Java 1.8 中不存在。
根据来自的 Java 1.8 文档ThreadPoolExecutor.execute():
/*
* 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.
* ....
*/
第二点,在加入一个worker到队列后,再检查一下,如果不是排队任务,可以启动一个新线程,而不是回滚入队并启动一个新线程。
这就是正在发生的事情。在第一次检查期间,任务已排队,但在重新检查期间,将启动一个新线程来执行您的任务。
添加回答
举报