面試官:知道線程池嗎
我:知道啊,然后准備回答,線程池原理及實現流程
面試官打斷:最近面試人挺多的,基本都知道原理,你給我講講keepAliveTime具體是怎樣實現非核心線程過期回收的。
我:.....(黑人問號)
面試完,迫不及待的打開源碼后,發現之前看源碼已經看過線程過期后怎樣銷毀的,但主要是想弄懂線程復用的原理,所以沒有注意。
前文源碼學習:Java並發包中的線程池ThreadPoolExecutor
一、線程過期銷毀
1、Worker.run():線程池線程復用的原理
final void runWorker(Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; w.unlock(); //將state設置為0,允許中斷 allow interrupts boolean completedAbruptly = true; try { //這里就是線程復用的實質,線程執行完提交的任務后,會不停從阻塞隊列workerQueue中獲取任務再執行
//跳出這里的循環,線程就不會復用,執行完runWorker方法后會被銷毀 while (task != null || (task = getTask()) != null) { w.lock();//worker不可重入獨占鎖 // 如果線程池正在停止Stopping,確保線程中斷 // 如果沒有,確保線程沒有被中斷 // 第二種情況需要復查處理 // 清除中斷時立即停止比賽 if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt(); try { //執行任務前操作--空方法預留擴展 beforeExecute(wt, task); Throwable thrown = null; try { //實際的任務運行command.run() 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 { //執行清理工作, //將當前線程完成任務數累加到總任務數上 //從workerSet中刪除當前工作線程 //嘗試終止線程池 //如果當前線程個數小於核心個數,創建線程 processWorkerExit(w, completedAbruptly); } }
2、線程過期銷毀
final void runWorker(Worker w) { Thread wt = Thread.currentThread(); //開始執行前會將work.firstTask = null,核心線程、非核心線程都是 Runnable task = w.firstTask; w.firstTask = null; w.unlock(); // allow interrupts boolean completedAbruptly = true; try { //一次循環后task == null,所以線程過期銷毀判斷關鍵在於getTask() while (task != null || (task = getTask()) != null) { w.lock(); if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt(); try { beforeExecute(wt, task); Throwable thrown = null; try { 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 task = null; w.completedTasks++; w.unlock(); } } completedAbruptly = false; } finally { processWorkerExit(w, completedAbruptly); } }
ThreadPoolExecutor.getTask()
private Runnable getTask() { boolean timedOut = false; // Did the last poll() time out? for (;;) { int c = ctl.get(); int rs = runStateOf(c); // Check if queue empty only if necessary. if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//如果工作隊列為空,線程池線程數減1,並返回null decrementWorkerCount(); return null; } int wc = workerCountOf(c); //worker工作線程會不會被回收
//① allowCoreThreadTimeOut == true,核心線程和非核心線程空閑keepAliveTime被銷毀,workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)
//② allowCoreThreadTimeOut == false,非核心線程空閑keepAliveTIme銷毀,workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)
// ,核心線程會被阻塞,不會被銷毀workQueue.take() boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) { if (compareAndDecrementWorkerCount(c)) return null; continue; } try { Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); if (r != null) return r; timedOut = true; } catch (InterruptedException retry) { timedOut = false; } } }
所以keepAliveTime具體是怎樣實現非核心線程過期銷毀的,是個很簡單的問題。有點后悔沒答上來
workQueue隊列為空,跳出循環,線程就會被銷毀。具體代碼通過阻塞隊列workQueue(keepAliveTime,TimeUnit.NANOSECONDS)實現控制線程存活時間的
線程銷毀的兩種場景:
① allowCoreThreadTimeOut == true,核心線程和非核心線程空閑keepAliveTime時被銷毀,workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)
② allowCoreThreadTimeOut == false,非核心線程空閑keepAliveTIme時被銷毀,workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)
核心線程永不銷毀的場景
① allowCoreThreadTimeOut == false,核心線程永不銷毀。workQueue.take()阻塞當前線程。