衡阳派盒市场营销有限公司

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何用interrupt停止線程

Android編程精選 ? 來源:CSDN ? 作者:CSDN ? 2022-05-04 17:18 ? 次閱讀
啟動(dòng)線程需要調(diào)用 Thread 類的 start() 方法,并在 run() 方法中定義需要執(zhí)行的任務(wù)。啟動(dòng)一個(gè)線程非常簡單,但如果想要正確停止它就沒那么容易了。

為什么不強(qiáng)制停止

對于 Java 而言,最正確的停止線程的方式是使用 interrupt。但 interrupt僅僅起到通知被停止線程的作用。而對于被停止的線程而言,它擁有完全的自主權(quán),它既可以選擇立即停止,也可以選擇一段時(shí)間后停止,也可以選擇壓根不停止。

為什么 Java 不提供強(qiáng)制停止線程的能力呢?

事實(shí)上,Java 希望程序間能夠相互通知、相互協(xié)作地管理線程,因?yàn)槿绻涣私鈱Ψ秸谧龅墓ぷ?,貿(mào)然強(qiáng)制停止線程就可能會(huì)造成一些安全的問題。

比如:

線程正在寫入一個(gè)文件,這時(shí)收到終止信號,它就需要根據(jù)自身業(yè)務(wù)判斷,是選擇立即停止,還是將整個(gè)文件寫入成功后停止。如果選擇立即停止就可能造成數(shù)據(jù)不完整,不管是中斷命令發(fā)起者,還是接收者都不希望數(shù)據(jù)出現(xiàn)問題。

如何用 interrupt 停止線程

while(!Thread.currentThread().isInterrupted()
&&moreworktodo){
domorework
}

我們一旦調(diào)用某個(gè)線程的 interrupt() 之后,這個(gè)線程的中斷標(biāo)記位就會(huì)被設(shè)置成 true。每個(gè)線程都有這樣的標(biāo)記位,當(dāng)線程執(zhí)行時(shí),應(yīng)該定期檢查這個(gè)標(biāo)記位,如果標(biāo)記位被設(shè)置成 true,就說明有程序想終止該線程。

回到源碼,可以看到在 while 循環(huán)體判斷語句中,首先通過 Thread.currentThread().isInterrupt() 判斷線程是否被中斷,隨后檢查是否還有工作要做。&& 邏輯表示只有當(dāng)兩個(gè)判斷條件同時(shí)滿足的情況下,才會(huì)去執(zhí)行下面的工作。

來段代碼瞅瞅。

publicclassStopThreadimplementsRunnable{

@Override
publicvoidrun(){
intcount=0;
while(!Thread.currentThread().isInterrupted()&&count1000){
System.out.println("count="+count++);
}
}

publicstaticvoidmain(String[]args)throwsInterruptedException{
Threadthread=newThread(newStopThread());
thread.start();
Thread.sleep(5);
thread.interrupt();
}
}

在 StopThread 類的 run() 方法中,首先判斷線程是否被中斷,然后判斷 count 值是否小于 1000。

這個(gè)線程的工作內(nèi)容很簡單,就是打印 0~999 的數(shù)字,每打印一個(gè)數(shù)字 count 值加 1,可以看到,線程會(huì)在每次循環(huán)開始之前,檢查是否被中斷了。接下來在 main 函數(shù)中會(huì)啟動(dòng)該線程,然后休眠 5 毫秒后立刻中斷線程,該線程會(huì)檢測到中斷信號,于是在還沒打印完1000個(gè)數(shù)的時(shí)候就會(huì)停下來,這種就屬于通過 interrupt 正確停止線程的情況。

sleep 期間能否感受到中斷

先說結(jié)論,可以。

publicclassStopDuringSleep{

publicstaticvoidmain(String[]args)throwsInterruptedException{
Runnablerunnable=()->{
intnum=0;
try{
while(!Thread.currentThread().isInterrupted()&&num<=?1000){
System.out.println(num);
num++;
Thread.sleep(1000000);
}
}catch(InterruptedExceptione){
e.printStackTrace();
}
};
Threadthread=newThread(runnable);
thread.start();
Thread.sleep(5);
thread.interrupt();
}
}

運(yùn)行后的結(jié)果你猜這么著,程序會(huì)拋出異常

ec708e1c-c3c3-11ec-bce3-dac502259ad0.png

如果 sleep、wait 等可以讓線程進(jìn)入阻塞的方法使線程休眠了,而處于休眠中的線程被中斷,那么線程是可以感受到中斷信號的,并且會(huì)拋出一個(gè) InterruptedException 異常,同時(shí)清除中斷信號,將中斷標(biāo)記位設(shè)置成 false。這樣一來就不用擔(dān)心長時(shí)間休眠中線程感受不到中斷了,因?yàn)榧幢憔€程還在休眠,仍然能夠響應(yīng)中斷通知,并拋出異常。

但是這樣只能相應(yīng)一次中斷信號了,怎么辦?

合理利用好 try/catch

我們在實(shí)際開發(fā)中不能盲目吞掉中斷,如果不在方法簽名中聲明,也不在 catch 語句塊中再次恢復(fù)中斷,而是在 catch 中不作處理,我們稱這種行為是“屏蔽了中斷請求”。如果我們盲目地屏蔽了中斷請求,會(huì)導(dǎo)致中斷信號被完全忽略,最終導(dǎo)致線程無法正確停止。

try{
Thread.sleep(2000);
}catch(InterruptedExceptione){
//此處處理中斷異常請求
}

停止線程的方式有幾種

  • void shutdown;
  • boolean isShutdown;
  • boolean isTerminated;
  • boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
  • List shutdownNow;

下面我們就對這些方法逐一展開。

shutdown()

調(diào)用 shutdown() 方法之后線程池并不是立刻就被關(guān)閉,因?yàn)檫@時(shí)線程池中可能還有很多任務(wù)正在被執(zhí)行,或是任務(wù)隊(duì)列中有大量正在等待被執(zhí)行的任務(wù),調(diào)用 shutdown() 方法后線程池會(huì)在執(zhí)行完正在執(zhí)行的任務(wù)和隊(duì)列中等待的任務(wù)后才徹底關(guān)閉。

但這并不代表 shutdown() 操作是沒有任何效果的,調(diào)用 shutdown() 方法后如果還有新的任務(wù)被提交,線程池則會(huì)根據(jù)拒絕策略直接拒絕后續(xù)新提交的任務(wù)。

isShutdown()

它可以返回 true 或者 false 來判斷線程池是否已經(jīng)開始了關(guān)閉工作,也就是是否執(zhí)行了 shutdown 或者 shutdownNow 方法。這里需要注意,如果調(diào)用 isShutdown() 方法的返回的結(jié)果為 true 并不代表線程池此時(shí)已經(jīng)徹底關(guān)閉了,這僅僅代表線程池開始了關(guān)閉的流程,也就是說,此時(shí)可能線程池中依然有線程在執(zhí)行任務(wù),隊(duì)列里也可能有等待被執(zhí)行的任務(wù)。

isTerminated()

這個(gè)方法可以檢測線程池是否真正“終結(jié)”了,這不僅代表線程池已關(guān)閉,同時(shí)代表線程池中的所有任務(wù)都已經(jīng)都執(zhí)行完畢了,因?yàn)槲覀儎偛耪f過,調(diào)用 shutdown 方法之后,線程池會(huì)繼續(xù)執(zhí)行里面未完成的任務(wù),不僅包括線程正在執(zhí)行的任務(wù),還包括正在任務(wù)隊(duì)列中等待的任務(wù)。

比如此時(shí)已經(jīng)調(diào)用了 shutdown 方法,但是有一個(gè)線程依然在執(zhí)行任務(wù),那么此時(shí)調(diào)用 isShutdown 方法返回的是 true ,而調(diào)用 isTerminated 方法返回的便是 false ,因?yàn)榫€程池中還有任務(wù)正在在被執(zhí)行,線程池并沒有真正“終結(jié)”。直到所有任務(wù)都執(zhí)行完畢了,調(diào)用 isTerminated() 方法才會(huì)返回 true,這表示線程池已關(guān)閉并且線程池內(nèi)部是空的,所有剩余的任務(wù)都執(zhí)行完畢了。

awaitTermination()

第四個(gè)方法叫作 awaitTermination(),它本身并不是用來關(guān)閉線程池的,而是主要用來判斷線程池狀態(tài)的。比如我們給 awaitTermination 方法傳入的參數(shù)是 10 秒,那么它就會(huì)陷入 10 秒鐘的等待,直到發(fā)生以下三種情況之一:

  • 等待期間(包括進(jìn)入等待狀態(tài)之前)線程池已關(guān)閉并目所有已提交的任務(wù)(包括正在執(zhí)行的和隊(duì)列中等待的都執(zhí)行完畢,相當(dāng)于線程池已經(jīng)“終結(jié)”了,方法便會(huì)返回true
  • 等待超時(shí)時(shí)間到后,第一種線程池“終結(jié)”的情況始終未發(fā)生,方法返回 false
  • 等待期間線程被中斷,方法會(huì)拋出 Interruptedexception異常

等待期間(包括進(jìn)入等待狀態(tài)之前)線程池已關(guān)閉并且所有已提交的任務(wù)(包括正在執(zhí)行的和隊(duì)列中等待的)都執(zhí)行完畢,相當(dāng)于線程池已經(jīng)“終結(jié)”了,方法便會(huì)返回 true;

等待超時(shí)時(shí)間到后,第一種線程池“終結(jié)”的情況始終未發(fā)生,方法返回 false;等待期間線程被中斷,方法會(huì)拋出 InterruptedException 異常。

shutdownNow()

最后一個(gè)方法是 shutdownNow(),也是 5 種方法里功能最強(qiáng)大的,它與第一種 shutdown 方法不同之處在于名字中多了一個(gè)單詞 Now,也就是表示立刻關(guān)閉的意思。參考這里:shutdown 和 shutdownNow 的區(qū)別

在執(zhí)行 shutdownNow 方法之后,首先會(huì)給所有線程池中的線程發(fā)送 interrupt 中斷信號,嘗試中斷這些任務(wù)的執(zhí)行,然后會(huì)將任務(wù)隊(duì)列中正在等待的所有任務(wù)轉(zhuǎn)移到一個(gè) List 中并返回,我們可以根據(jù)返回的任務(wù) List 來進(jìn)行一些補(bǔ)救的操作,例如記錄在案并在后期重試。

publicListshutdownNow(){
Listtasks;
finalReentrantLockmainLock=this.mainLock;
mainLock.lock();

try{
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers();
tasks=drainQueue();
}finally{
mainLock.unlock();
}

tryTerminate();
returntasks;
}

源碼中有一行 interruptWorkers() 代碼,這行代碼會(huì)讓每一個(gè)已經(jīng)啟動(dòng)的線程都中斷,這樣線程就可以在執(zhí)行任務(wù)期間檢測到中斷信號并進(jìn)行相應(yīng)的處理,提前結(jié)束任務(wù)。

這里需要注意的是,由于 Java 中不推薦強(qiáng)行停止線程的機(jī)制的限制,即便我們調(diào)用了 shutdownNow 方法,如果被中斷的線程對于中斷信號不理不睬,那么依然有可能導(dǎo)致任務(wù)不會(huì)停止。

總結(jié)

中斷和關(guān)閉線程的方式五花八門,看起來很相似,其實(shí)里頭大有門道。處理不好,可是會(huì)導(dǎo)致程序崩潰的。

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2975

    瀏覽量

    105151
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    505

    瀏覽量

    19758

原文標(biāo)題:如何正確的停掉線程?這里面大有門道!

文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    socket 多線程編程實(shí)現(xiàn)方法

    在現(xiàn)代網(wǎng)絡(luò)編程中,多線程技術(shù)被廣泛應(yīng)用于提高服務(wù)器的并發(fā)處理能力。Socket編程是網(wǎng)絡(luò)通信的基礎(chǔ),而將多線程技術(shù)應(yīng)用于Socket編程,可以顯著提升服務(wù)器的性能。 多線程編程的基本概念 多
    的頭像 發(fā)表于 11-12 14:16 ?468次閱讀

    Python中多線程和多進(jìn)程的區(qū)別

    Python作為一種高級編程語言,提供了多種并發(fā)編程的方式,其中多線程與多進(jìn)程是最常見的兩種方式之一。在本文中,我們將探討Python中多線程與多進(jìn)程的概念、區(qū)別以及如何使用線程池與進(jìn)程池來提高并發(fā)執(zhí)行效率。
    的頭像 發(fā)表于 10-23 11:48 ?495次閱讀
    Python中多<b class='flag-5'>線程</b>和多進(jìn)程的區(qū)別

    CPU線程和程序線程的區(qū)別

    CPU的線程與程序的線程在概念、作用、實(shí)現(xiàn)方式以及性能影響等方面存在顯著差異。以下是對兩者區(qū)別的詳細(xì)闡述,旨在深入探討這一技術(shù)話題。
    的頭像 發(fā)表于 09-02 11:18 ?1205次閱讀

    鴻蒙開發(fā):線程模型

    FA模型下的線程主要有如下三類
    的頭像 發(fā)表于 06-24 17:27 ?480次閱讀
    鴻蒙開發(fā):<b class='flag-5'>線程</b>模型

    探索虛擬線程:原理與實(shí)現(xiàn)

    虛擬線程的引入與優(yōu)勢 在Loom項(xiàng)目之前,Java虛擬機(jī)(JVM)中的線程是通過java.lang.Thread類型來實(shí)現(xiàn)的,這些線程被稱為平臺(tái)線程。 然而,平臺(tái)
    的頭像 發(fā)表于 06-24 11:35 ?360次閱讀
    探索虛擬<b class='flag-5'>線程</b>:原理與實(shí)現(xiàn)

    鴻蒙開發(fā):停止PageAbility

    停止PageAbility通過featureAbility中的terminateSelf接口實(shí)現(xiàn)。
    的頭像 發(fā)表于 06-18 14:16 ?359次閱讀
    鴻蒙開發(fā):<b class='flag-5'>停止</b>PageAbility

    鴻蒙開發(fā):【線程模型】

    管理其他線程的ArkTS引擎實(shí)例,例如使用TaskPool(任務(wù)池)創(chuàng)建任務(wù)或取消任務(wù)、啟動(dòng)和終止Worker線程。
    的頭像 發(fā)表于 06-13 16:38 ?459次閱讀
    鴻蒙開發(fā):【<b class='flag-5'>線程</b>模型】

    鴻蒙APP開發(fā):【ArkTS類庫多線程】TaskPool和Worker的對比(2)

    創(chuàng)建Worker的線程稱為宿主線程(不一定是主線程,工作線程也支持創(chuàng)建Worker子線程),Worker自身的
    的頭像 發(fā)表于 03-27 15:44 ?578次閱讀
    鴻蒙APP開發(fā):【ArkTS類庫多<b class='flag-5'>線程</b>】TaskPool和Worker的對比(2)

    java實(shí)現(xiàn)多線程的幾種方式

    Java實(shí)現(xiàn)多線程的幾種方式 多線程是指程序中包含了兩個(gè)或以上的線程,每個(gè)線程都可以并行執(zhí)行不同的任務(wù)或操作。Java中的多線程可以提高程序
    的頭像 發(fā)表于 03-14 16:55 ?783次閱讀

    python中5種線程鎖盤點(diǎn)

    線程安全是多線程或多進(jìn)程編程中的一個(gè)概念,在擁有共享數(shù)據(jù)的多條線程并行執(zhí)行的程序中,線程安全的代碼會(huì)通過同步機(jī)制保證各個(gè)線程都可以正常且正確
    發(fā)表于 03-07 11:08 ?1671次閱讀
    python中5種<b class='flag-5'>線程</b>鎖盤點(diǎn)

    FX3/CX3(CYUSB3065) 線程停止是什么原因,有辦法解決嗎?

    我使用FX3/CX3(CYUSB3065) 通過DMA的方式來攝像,然后用一組 I2C來控制攝像的配置, 同時(shí)這組I2C還控制另一顆芯片,這顆芯片需要不定時(shí)的訪問, 然后線程就不再被調(diào)起了(攝像也
    發(fā)表于 02-29 08:19

    什么是動(dòng)態(tài)線程池?動(dòng)態(tài)線程池的簡單實(shí)現(xiàn)思路

    因此,動(dòng)態(tài)可監(jiān)控線程池一種針對以上痛點(diǎn)開發(fā)的線程池管理工具。主要可實(shí)現(xiàn)功能有:提供對 Spring 應(yīng)用內(nèi)線程池實(shí)例的全局管控、應(yīng)用運(yùn)行時(shí)動(dòng)態(tài)變更線程池參數(shù)以及
    的頭像 發(fā)表于 02-28 10:42 ?722次閱讀

    RTT Nano線程創(chuàng)建成功,沒有進(jìn)入線程創(chuàng)建的函數(shù)運(yùn)行怎么解決?

    RTT Nano線程創(chuàng)建成功,沒有進(jìn)入線程創(chuàng)建的函數(shù)運(yùn)行int main(void) { interrupt_config(); // gd_eval_led_init(LED1
    發(fā)表于 02-26 06:27

    linux多線程編程實(shí)例

    linux線程
    的頭像 發(fā)表于 02-15 21:16 ?529次閱讀
    linux多<b class='flag-5'>線程</b>編程實(shí)例

    arduino如何停止loop循環(huán)

    Arduino的loop循環(huán)是其主要的程序執(zhí)行部分,該循環(huán)將在Arduino開發(fā)板上持續(xù)運(yùn)行,并且只有在程序被重新上傳或開發(fā)板斷電重啟時(shí)才會(huì)停止。然而,在某些情況下,你可能需要在程序執(zhí)行過程中停止
    的頭像 發(fā)表于 02-14 16:24 ?4713次閱讀
    大发888赌场的微博| 百家乐国际娱乐场开户注册| 百家乐官网投注杀手| 大发888娱乐大发体育| 百家乐怎么玩啊| 百家乐官网下对子的概率| 大发888娱乐城健账号| 百家乐什么牌最大| 新2百家乐官网娱乐城| 永盈会娱乐场官网| 百家乐赌博彩| 百家乐官网娱乐平台真钱游戏| 利高在线娱乐城| 百家乐是真人发牌吗| 百家乐娱乐城信息| 百家乐官网系列抢庄龙| 赌博技术| 成都百家乐牌具| 百家乐网站开户| 豪华百家乐官网人桌| 注册送现金| 大发888娱乐城建账号| 百家乐7杀6| 博之道百家乐官网的玩法技巧和规则 | 大发888送钱58元| 百家乐开发软件| 百家乐官网和的打法| 百家乐官网网址哪里有| 寒江博彩堂| 百家乐创立几年了| 百家乐赌神| 华泰百家乐官网的玩法技巧和规则| 新世纪百家乐官网现金网| 菲律宾凤凰娱乐| 百家乐园天将| 同乐城百家乐现金网| 线上百家乐官网是如何作弊| 专业百家乐官网分析| 辽宁棋牌游戏大厅| 威尼斯人娱乐场开户注册| 百家乐赌博公司|