日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
如何優(yōu)雅的「打斷」你的線程?

最近看了點(diǎn) psi-Probe的源代碼,在線程列表頁面,可以對頁面中各個(gè)進(jìn)行線程管理,其中有這樣一個(gè)操作,見最左側(cè)藍(lán)色方框:

創(chuàng)新互聯(lián)建站是一家專注網(wǎng)站建設(shè)、網(wǎng)絡(luò)營銷策劃、重慶小程序開發(fā)、電子商務(wù)建設(shè)、網(wǎng)絡(luò)推廣、移動(dòng)互聯(lián)開發(fā)、研究、服務(wù)為一體的技術(shù)型公司。公司成立10年以來,已經(jīng)為成百上千家成都酒店設(shè)計(jì)各業(yè)的企業(yè)公司提供互聯(lián)網(wǎng)服務(wù)。現(xiàn)在,服務(wù)的成百上千家客戶與我們一路同行,見證我們的成長;未來,我們一起分享成功的喜悅。

點(diǎn)擊每個(gè)線程對應(yīng)的箭頭按鈕,會(huì)彈出下方的提示:

實(shí)際這上按鈕的操作,是要 「Kill」這個(gè)指定的線程。

順著鏈接,我們能看到,具體的實(shí)現(xiàn)是這個(gè)樣子:

 
 
 
 
  1. String threadName = ServletRequestUtils.getStringParameter(request, "thread", null); 
  2.  
  3. Thread thread = null; 
  4. if (threadName != null) { 
  5.   thread = Utils.getThreadByName(threadName); 
  6.  
  7. if (thread != null) { 
  8.   thread.stop(); 

正如前面的彈窗提示,這里果然調(diào)用的是個(gè)危險(xiǎn)操作:

 
 
 
 
  1. Thread.stop() 

這里的 「stop」方法,和「resume」方法、「suspend」方法并稱 Thread 三少,因?yàn)榫€程安全問題,都已經(jīng)被 @Deprecated 了。

官方文檔說的好:

Stopping a thread causes it to unlock all the monitors that it has locked

當(dāng)我們停止一個(gè)線程時(shí),它會(huì)悄悄的把所持有的 monitor 鎖釋放了,此時(shí),其他依賴鎖的線程可能就會(huì)搶到鎖執(zhí)行。關(guān)鍵此時(shí),當(dāng)前 stop 的線程實(shí)際并沒有處理完所有先決條件,可能這個(gè)時(shí)候就產(chǎn)生了詭異的問題,加班的日子可能就悄悄來了。

那你說 「Stop 不讓用了,總得讓我們有辦法處理線程吧,哪怕通知他,打斷他一下,讓他停止」。

目前有以下幾種方式來實(shí)現(xiàn)。

異常

這點(diǎn) Thread 也想到了,提供了一個(gè)「異?!箒磉_(dá)到這個(gè)打斷的目的。這個(gè)異常在其他線程要打斷某個(gè)特定線程時(shí)執(zhí)行,如果是符合條件,會(huì)拋出來。此時(shí)這個(gè)特定線程自行根據(jù)這次打斷來判斷后續(xù)是不是要再執(zhí)行線程內(nèi)的邏輯,還是直接跳出處理。

這個(gè)異常就是 InterruptedException。一般使用方式類似這樣

 
 
 
 
  1. try { 
  2.     Thread.sleep(backgroundProcessorDelay * 1000L); 
  3. } catch (InterruptedException e) { 
  4.     // 具體在中斷通知后的操作 
  5.      
  6.  xxxThread.interrupt();   

目前有以下方法能夠進(jìn)行這種操作

  • Thread.sleep
  • Thread.join
  • Object.wait

以wait方法為例,我們來看文檔里的描述

 
 
 
 
  1. * @throws  InterruptedException if any thread interrupted the 
  2. *             current thread before or while the current thread 
  3. *             was waiting for a notification.  The interrupted 
  4. *             status of the current thread is cleared when 
  5. *             this exception is thrown. 

這里有一點(diǎn)信息: 「interrupted status」,這個(gè)是個(gè)狀態(tài)標(biāo)識(shí),在Thread類中,可以通過 isInterrupted來判斷當(dāng)前線程是否被中斷。這個(gè)標(biāo)識(shí)也可以用來作為一個(gè)退出線程執(zhí)行的標(biāo)識(shí)來直接使用。 但例外是阻塞方法在收到中斷方法調(diào)用后,這個(gè)標(biāo)識(shí)會(huì)被清除重置,所以需要注意下。

我們在執(zhí)行阻塞方法線程的interrupt方法時(shí),此時(shí)并不能拿到這個(gè)標(biāo)識(shí)。

另外,拿到異常時(shí),需要關(guān)注,如果是類似于后臺(tái)循環(huán)執(zhí)行的調(diào)度線程,在收到中斷異常時(shí)需要處理異常再 break 才能跳出,否則只是相當(dāng)于一個(gè)空操作。

目前一些程序里用這種的倒不多,用下面這種的多一些。

退出標(biāo)識(shí)

對于一些長駐線程,會(huì)在某些時(shí)候需要退出執(zhí)行,這種情況下,常采用的操作類似這樣, 以Tomcat 的NioConnector 里的Acceptor為例:

 
 
 
 
  1. protected class Acceptor extends AbstractEndpoint.Acceptor { 
  2.  
  3.     @Override 
  4.     public void run() { 
  5.  
  6.         int errorDelay = 0; 
  7.  
  8.         // Loop until we receive a shutdown command 
  9.         while (running) {   // 標(biāo)識(shí)1 
  10.  
  11.             // Loop if endpoint is paused 
  12.             while (paused && running) {   // 標(biāo)識(shí)2 
  13.                 state = AcceptorState.PAUSED; 
  14.                 try { 
  15.                     Thread.sleep(50); 
  16.                 } catch (InterruptedException e) { 
  17.                     // Ignore 
  18.                 } 
  19.             } 
  20.  
  21.             if (!running) { 
  22.                 break; 
  23.             } 
  24.             ... 
  25.         }     

用這種退出標(biāo)識(shí)時(shí),記得一定要聲明為 volatile ,類似這樣:

 
 
 
 
  1. /** 
  2.  * Running state of the endpoint. 
  3.  */ 
  4. protected volatile boolean running = false; 
  5.  
  6.  
  7. /** 
  8.  * Will be set to true whenever the endpoint is paused. 
  9.  */ 
  10. protected volatile boolean paused = false; 

否則因?yàn)槎嗑€程的可見性問題, 這個(gè)線程可能一直都不會(huì)退出。

目前在 Tomcat 使用中,無法在運(yùn)行時(shí)直接操作 Connector ,所以一般情況這個(gè) pause 標(biāo)識(shí)可能沒法設(shè)置。但有幾種觸發(fā)的方式,一種是通過 JConsole 等工具連接到 MBeanServer 上,直接通過其MBean方法操作pause,來改變值,另一種是使用類似 psi-Probe(一款功能強(qiáng)大的Tomcat 管理監(jiān)控工具)這種管理控制臺(tái),之前我已經(jīng)把可以操作 Connector 狀態(tài)的代碼提交給 github上(怎樣參與到全世界優(yōu)秀的開源項(xiàng)目中?),commiter 已經(jīng)合入??梢允褂眠M(jìn)行狀態(tài)改變觀察。

總體來說,如果處理sleep/wait等操作,擔(dān)心時(shí)間太長,可以通過 interrupt 來進(jìn)行,對于駐留線程,可以通過退出標(biāo)識(shí)來處理。

【本文為專欄作者“侯樹成”的原創(chuàng)稿件,轉(zhuǎn)載請通過作者微信公眾號(hào)『Tomcat那些事兒』獲取授權(quán)】


文章題目:如何優(yōu)雅的「打斷」你的線程?
文章分享:http://www.5511xx.com/article/ccdhiis.html