3 回答

TA貢獻2012條經(jīng)驗 獲得超12個贊
在 jdk 1.5、1.6、1.7 和 1.8 中運行這個程序時,我發(fā)現(xiàn)ThreadPoolExecutor#execute(Runnable)了 1.5、1.6 和 1.7+ 中的不同實現(xiàn)。這是我發(fā)現(xiàn)的:
JDK 1.5 實現(xiàn)
//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
}
}
當(dāng)corePoolSize為 0 時,此實現(xiàn)不會創(chuàng)建線程,因此不會執(zhí)行提供的任務(wù)。
JDK 1.6 實現(xiàn)
//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 也會創(chuàng)建一個新線程。
JDK 1.7+ 實現(xiàn)(類似于 JDK 1.6,但具有更好的鎖和狀態(tài)檢查)
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 也會創(chuàng)建一個新線程。
因此,corePoolSize=0在 JDK 1.5 和 JDK 1.6+ 的每個版本中,這似乎都是一個特例。
但奇怪的是,書中的解釋與任何程序結(jié)果都不符。

TA貢獻1834條經(jīng)驗 獲得超8個贊
似乎這是舊 Java 版本的錯誤,但現(xiàn)在在 Java 1.8 中不存在。
根據(jù)來自的 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到隊列后,再檢查一下,如果不是排隊任務(wù),可以啟動一個新線程,而不是回滾入隊并啟動一個新線程。
這就是正在發(fā)生的事情。在第一次檢查期間,任務(wù)已排隊,但在重新檢查期間,將啟動一個新線程來執(zhí)行您的任務(wù)。
添加回答
舉報