更新時間:2022-12-09 15:00:17 來源:動力節(jié)點 瀏覽1998次
你是否已經(jīng)準(zhǔn)備好跳槽了呢,是否期望自己拿到更高的薪資呢,是否有望獲得心儀的offer呢!那么,今天這套Java面試題是你不二之選,本篇題目總結(jié)了在各大一線互聯(lián)網(wǎng)公司面試官的出題經(jīng)驗,深剖核心問題,多角度的去挖掘后,為大呈現(xiàn)出來的:
考慮到系統(tǒng)資源是有限的,對于線程池超出 corePoolSize 數(shù)量的空閑線程應(yīng)進行回收操作。進行此操作存在一個問題,即回收時機。目前的實現(xiàn)方式是當(dāng)線程空閑時間超過 keepAliveTime 后,進行回收。除了核心線程數(shù)之外的線程可以進行回收,核心線程內(nèi)的空閑線程也可以進行回收。回收的前提是allowCoreThreadTimeOut屬性被設(shè)置為 true,通過public void allowCoreThreadTimeOut(boolean) 方法可以設(shè)置屬性值。
如 3.1.2 線程創(chuàng)建規(guī)則一節(jié)中規(guī)則 2 所說,當(dāng)線程數(shù)量大于等于 corePoolSize,workQueue 未滿時,則緩存新任務(wù)。這里要考慮使用什么類型的容器緩存新任務(wù),通過 JDK 文檔介紹,我們可知道有 3 中類型的容器可供使用,分別是同步隊列,有界隊列和無界隊列。對于有優(yōu)先級的任務(wù),這里還可以增加優(yōu)先級隊列。以上所介紹的 4 中類型的隊列,對應(yīng)的實現(xiàn)類如下:
| 實現(xiàn)類 | 類型 | 說明 |
| --- | --- | --- |
| SynchronousQueue | 同步隊列 | 該隊列不存儲元素,每個插入操作必須等待另一個線程調(diào)用移除操作,否則插入操作會一直阻塞 |
| ArrayBlockingQueue | 有界隊列 | 基于數(shù)組的阻塞隊列,按照 FIFO 原則對元素進行排序 |
| LinkedBlockingQueue | 無界隊列 | 基于鏈表的阻塞隊列,按照 FIFO 原則對元素進行排序 |
| PriorityBlockingQueue | 優(yōu)先級隊列 | 具有優(yōu)先級的阻塞隊列 |
如 3.1.2 線程創(chuàng)建規(guī)則一節(jié)中規(guī)則 4 所說,線程數(shù)量大于等于 maximumPoolSize,且 workQueue 已滿,則使用拒絕策略處理新任務(wù)。Java 線程池提供了 4 中拒絕策略實現(xiàn)類,如下:
| 實現(xiàn)類 | 說明 |
| --- | --- |
| AbortPolicy | 丟棄新任務(wù),并拋出?RejectedExecutionException |
| DiscardPolicy | 不做任何操作,直接丟棄新任務(wù) |
| DiscardOldestPolicy | 丟棄隊列隊首的元素,并執(zhí)行新任務(wù) |
| CallerRunsPolicy | 由調(diào)用線程執(zhí)行新任務(wù) |
以上 4 個拒絕策略中,AbortPolicy 是線程池實現(xiàn)類所使用的策略。我們也可以通過方法public void setRejectedExecutionHandler(RejectedExecutionHandler)修改線程池決絕策略。
在線程池的實現(xiàn)上,線程的創(chuàng)建是通過線程工廠接口ThreadFactory的實現(xiàn)類來完成的。默認(rèn)情況下,線程池使用Executors.defaultThreadFactory()方法返回的線程工廠實現(xiàn)類。當(dāng)然,我們也可以通過
public void setThreadFactory(ThreadFactory)方法進行動態(tài)修改。具體細(xì)節(jié)這里就不多說了,并不復(fù)雜,大家可以自己去看下源碼。
在線程池中,線程的復(fù)用是線程池的關(guān)鍵所在。這就要求線程在執(zhí)行完一個任務(wù)后,不能立即退出。對應(yīng)到具體實現(xiàn)上,工作線程在執(zhí)行完一個任務(wù)后,會再次到任務(wù)隊列獲取新的任務(wù)。如果任務(wù)隊列中沒有任務(wù),且 keepAliveTime 也未被設(shè)置,工作線程則會被一致阻塞下去。通過這種方式即可實現(xiàn)線程復(fù)用。
說完原理,再來看看線程的創(chuàng)建和復(fù)用的相關(guān)代碼(基于 JDK 1.8),如下:
`+----ThreadPoolExecutor.Worker.java Worker(Runnable firstTask) {
setState(-1);
this.firstTask = firstTask;
// 調(diào)用線程工廠創(chuàng)建線程
this.thread = getThreadFactory().newThread(this);
}
// Worker 實現(xiàn)了 Runnable 接口
public void run() {
runWorker(this);
}
+----ThreadPoolExecutor.java final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock();
boolean completedAbruptly = true;
try {
// 循環(huán)從任務(wù)隊列中獲取新任務(wù)
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
// 執(zhí)行新任務(wù)
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
// 線程退出后,進行后續(xù)處理
processWorkerExit(w, completedAbruptly);
}
}`
以上就是“一線大廠總結(jié)出的Java項目經(jīng)理面試題”,你能回答上來嗎?如果想要了解更多的Java面試題相關(guān)內(nèi)容,可以關(guān)注動力節(jié)點Java官網(wǎng)。