您好,登錄后才能下訂單哦!
本篇內容介紹了“Java線程池怎么實現優雅退出”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
當使用線程池的時候,調用了shutdown()方法后,線程池就不會再接受新的執行任務了。但是在調用shutdown()方法之前放入任務隊列中的任務還是要執行的。此方法是非阻塞方法,調用后會立即返回,并不會等待任務隊列中的任務全部執行完畢后再返回。我們看下shutdown()方法的源代碼,如下所示。
public void shutdown() { //獲取線程池的全局鎖 final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //檢查是否有關閉線程池的權限 checkShutdownAccess(); //將當前線程池的狀態設置為SHUTDOWN advanceRunState(SHUTDOWN); //中斷Worker線程 interruptIdleWorkers(); //為ScheduledThreadPoolExecutor調用鉤子函數 onShutdown(); // hook for } finally { //釋放線程池的全局鎖 mainLock.unlock(); } //嘗試將狀態變為TERMINATED tryTerminate(); }
總體來說,shutdown()方法的代碼比較簡單,首先檢查了是否有權限來關閉線程池,如果有權限,則再次檢測是否有中斷工作線程的權限,如果沒有權限,則會拋出SecurityException異常,代碼如下所示。
//檢查是否有關閉線程池的權限 checkShutdownAccess(); //將當前線程池的狀態設置為SHUTDOWN advanceRunState(SHUTDOWN); //中斷Worker線程 interruptIdleWorkers();
其中,checkShutdownAccess()方法的實現代碼如下所示。
private void checkShutdownAccess() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(shutdownPerm); final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) security.checkAccess(w.thread); } finally { mainLock.unlock(); } } }
對于checkShutdownAccess()方法的代碼理解起來比較簡單,就是檢測是否具有關閉線程池的權限,期間使用了線程池的全局鎖。
接下來,我們看advanceRunState(int)方法的源代碼,如下所示。
private void advanceRunState(int targetState) { for (;;) { int c = ctl.get(); if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) break; } }
advanceRunState(int)方法的整體邏輯就是:判斷當前線程池的狀態是否為指定的狀態,在shutdown()方法中傳遞的狀態是SHUTDOWN,如果是SHUTDOWN,則直接返回;如果不是SHUTDOWN,則將當前線程池的狀態設置為SHUTDOWN。
接下來,我們看看showdown()方法調用的interruptIdleWorkers()方法,如下所示。
private void interruptIdleWorkers() { interruptIdleWorkers(false); }
可以看到,interruptIdleWorkers()方法調用的是interruptIdleWorkers(boolean)方法,繼續看interruptIdleWorkers(boolean)方法的源代碼,如下所示。
private void interruptIdleWorkers(boolean onlyOne) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) { Thread t = w.thread; if (!t.isInterrupted() && w.tryLock()) { try { t.interrupt(); } catch (SecurityException ignore) { } finally { w.unlock(); } } if (onlyOne) break; } } finally { mainLock.unlock(); } }
上述代碼的總體邏輯為:獲取線程池的全局鎖,循環所有的工作線程,檢測線程是否被中斷,如果沒有被中斷,并且Worker線程獲得了鎖,則執行線程的中斷方法,并釋放線程獲取到的鎖。此時如果onlyOne參數為true,則退出循環。否則,循環所有的工作線程,執行相同的操作。最終,釋放線程池的全局鎖。
接下來,我們看下shutdownNow()方法。
如果調用了線程池的shutdownNow()方法,則線程池不會再接受新的執行任務,也會將任務隊列中存在的任務丟棄,正在執行的Worker線程也會被立即中斷,同時,方法會立刻返回,此方法存在一個返回值,也就是當前任務隊列中被丟棄的任務列表。
shutdownNow()方法的源代碼如下所示。
public List<Runnable> shutdownNow() { List<Runnable> tasks; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //檢查是否有關閉權限 checkShutdownAccess(); //設置線程池的狀態為STOP advanceRunState(STOP); //中斷所有的Worker線程 interruptWorkers(); //將任務隊列中的任務移動到tasks集合中 tasks = drainQueue(); } finally { mainLock.unlock(); } /嘗試將狀態變為TERMINATED tryTerminate(); //返回tasks集合 return tasks; }
shutdownNow()方法的源代碼的總體邏輯與shutdown()方法基本相同,只是shutdownNow()方法將線程池的狀態設置為STOP,中斷所有的Worker線程,并且將任務隊列中的所有任務移動到tasks集合中并返回。
可以看到,shutdownNow()方法中斷所有的線程時,調用了interruptWorkers()方法,接下來,我們就看下interruptWorkers()方法的源代碼,如下所示。
private void interruptWorkers() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) w.interruptIfStarted(); } finally { mainLock.unlock(); } }
interruptWorkers()方法的邏輯比較簡單,就是獲得線程池的全局鎖,循環所有的工作線程,依次中斷線程,最后釋放線程池的全局鎖。
在interruptWorkers()方法的內部,實際上調用的是Worker類的interruptIfStarted()方法來中斷線程,我們看下Worker類的interruptIfStarted()方法的源代碼,如下所示。
void interruptIfStarted() { Thread t; if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { try { t.interrupt(); } catch (SecurityException ignore) { } } }
發現其本質上調用的還是Thread類的interrupt()方法來中斷線程。
當線程池調用了awaitTermination(long, TimeUnit)方法后,會阻塞調用者所在的線程,直到線程池的狀態修改為TERMINATED才返回,或者達到了超時時間返回。接下來,我們看下awaitTermination(long, TimeUnit)方法的源代碼,如下所示。
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { //獲取距離超時時間剩余的時長 long nanos = unit.toNanos(timeout); //獲取Worker線程的的全局鎖 final ReentrantLock mainLock = this.mainLock; //加鎖 mainLock.lock(); try { for (;;) { //當前線程池狀態為TERMINATED狀態,會返回true if (runStateAtLeast(ctl.get(), TERMINATED)) return true; //達到超時時間,已超時,則返回false if (nanos <= 0) return false; //重置距離超時時間的剩余時長 nanos = termination.awaitNanos(nanos); } } finally { //釋放鎖 mainLock.unlock(); } }
上述代碼的總體邏輯為:首先獲取Worker線程的獨占鎖,后在循環判斷當前線程池是否已經是TERMINATED狀態,如果是則直接返回true,否則檢測是否已經超時,如果已經超時,則返回false。如果未超時,則重置距離超時時間的剩余時長。接下來,進入下一輪循環,再次檢測當前線程池是否已經是TERMINATED狀態,如果是則直接返回true,否則檢測是否已經超時,如果已經超時,則返回false。如果未超時,則重置距離超時時間的剩余時長。以此循環,直到線程池的狀態變為TERMINATED或者已經超時。
“Java線程池怎么實現優雅退出”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。