线程池什么时候调用shutdown方法_ThreadPoolExecutor.shutdown()?
1.導語
最近在工作中,有遇到下面這樣一段代碼,某個同事一看到代碼中的shutdown(),馬上就斷定這代碼執行不了,我問為什么這么說,他說線程池都關了,這任務怎么執行?不能說沒有問題,但事實真如他所說嗎,我們來探一探shutdown()的虛實。
簡單代碼
2.shutdown 源碼
shutdown 源碼
從shutdown 源碼的注釋我們可以看到,它會初始化一個順序的已提交的任務的關閉操作,并且不再接受新的任務;如果線程池已經被showdown了,那么該方法的調用將沒有任何的效果了。
下面我來對showdown內部調用的方法做個解析。
checkShutdownAccess
checkShutdownAccess
這個方法其實沒什么說的,比較簡單,就是對workers的線程做一個安全權限檢查。
advanceRunState
advanceRunState
該方法通過cas操作設置runState。如果當前的線程池的狀態值大于給定的值,,也即是runStateAtLeast(c, targetState) 返回true ,那么就不做任何操作了,直接break;如果返回false,那么就看ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))) 設置是否成功,否則一直重復這個過程。
interruptIdleWorkers
interruptIdleWorkers
里面有一個interruptIdleWorkers 方法,默認傳了false。傳false的意思是把,在獲取鎖的情況下,把workers的線程都執行interrupt()操作。
interruptIdleWorkers
interruptIdleWorkers
注釋說明,中斷可能正在等待任務的線程(表示沒有被鎖定)以便他們可以檢查終止或配置更改。忽略SecurityExceptions(在這種情況下,某些線程可能會保留不間斷)。
如果線程沒有被interrupt 并且tryLock到鎖了,那么就可以判定這是一個IdleWorkers,將會執行interrupt() 方法。如果worker線程在執行任務,runWorker方法中中執行的Worker是占有鎖的,這里也就無法獲取到鎖,即tryLock不到,就是非IdleWorkers。
tryTerminate
tryTerminate
先看注釋,如果線程池狀態是shutdown并且線程池和隊列是空的,或者線程池是stop狀態并且線程池是空的,把他改為terminate狀態;如果線程池可以被terminate,但是workerCount 不為0,終止一個dle worker來確保 shutdown 信號傳遞下去。該方法一定要跟在任何可能會使terminate的操作之后----減少worker count 或在showdow中從隊列中移除任務。
if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) return;//如果線程池的狀態是isRunning,或者狀態值>=TIDYING,或者SHUTDOWN并且workQueue不為//空,直接返回if (workerCountOf(c) != 0) { // Eligible to terminate interruptIdleWorkers(ONLY_ONE); return; }//如果workerCountOf 不為0,表示可以被terminate,interruptIdleWorkers(true) 線程后將 //shutdown 信號傳遞下去。if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { try { terminated(); } finally { ctl.set(ctlOf(TERMINATED, 0)); termination.signalAll(); } return;}//這里通過cas 將狀態設置為TIDYING,如果成功則調用 terminated()方法,執行成功后,最后 將狀態//設置為TERMINATED,并喚醒awaitTermination中等待的線程。實例
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, 10, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5)); for (int i = 0; i < 5; i++) { poolExecutor.submit(new MyTask()); } poolExecutor.shutdown();try { //5秒后關閉 poolExecutor.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { System.out.println(e.getMessage()); }*/class MyTask implements Runnable { @Override public void run() { try { System.out.println(Thread.currentThread().getName()); Thread.sleep(3000); }catch (Exception e) { System.out.println(e.getMessage()); } }}小結
通過以上的一些分析,當然不夠全面,還有一些方法沒有說明,以及一個demo,我們可以看到線程池關閉都能正確輸出結果。線程池關閉的關鍵就在于一個worker退出后會調用tryTerminate(),將這種信號傳遞下去,其他的線程才能被依次處理,最終塵歸塵,變為 Terminate。
好了,喜歡的朋友點贊+關注+轉發,與小編共同成長[奮斗][奮斗][奮斗]
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的线程池什么时候调用shutdown方法_ThreadPoolExecutor.shutdown()?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安庆蓝莓基地在哪里?
- 下一篇: 炒猪肚的家常做法?