InterruptedException和中断线程的说明
如果沒有將InterruptedException檢查為異常,則可能甚至沒人會(huì)注意到它-這實(shí)際上可以防止這些年來的幾個(gè)錯(cuò)誤。 但是由于必須對(duì)其進(jìn)行處理,因此許多人不正確或不加考慮地處理它。 讓我們以一個(gè)線程的簡(jiǎn)單示例為例,該線程定期進(jìn)行一些清理,但大多數(shù)情況下在兩次睡眠之間進(jìn)行。
此代碼在很多層上都是錯(cuò)誤的!
所有問題都是有效的,但是吞下InterruptedException是其最大的罪過。 在我們理解原因之前,讓我們先思考一下該異常的含義以及如何利用它來優(yōu)雅地中斷線程。 JDK中的許多阻止操作都聲明拋出InterruptedException ,包括:
- Object.wait()
- Thread.sleep()
- Process.waitFor()
- AsynchronousChannelGroup.awaitTermination()
- java.util.concurrent.*各種阻塞方法,例如ExecutorService.awaitTermination() , Future.get() , BlockingQueue.take() , Semaphore.acquire() Condition.await()以及許多其他方法
- SwingUtilities.invokeAndWait()
請(qǐng)注意,阻塞I / O不會(huì)引發(fā)InterruptedException (這很可惜)。 如果所有這些類都聲明了InterruptedException ,那么您可能想知道何時(shí)會(huì)拋出此異常?
- 當(dāng)某個(gè)線程在聲明InterruptedException某些方法上被阻塞并且您在該線程上調(diào)用Thread.interrupt()時(shí),很可能阻塞的方法將立即引發(fā)InterruptedException 。
- 如果將任務(wù)提交到線程池( ExecutorService.submit() ),并且在執(zhí)行任務(wù)時(shí)調(diào)用Future.cancel(true) 。 在這種情況下,線程池將嘗試為您中斷正在運(yùn)行該任務(wù)的線程,從而有效地中斷您的任務(wù)。
知道InterruptedException實(shí)際含義后,我們就能夠正確地處理它。 如果有人試圖中斷我們的線程,而我們通過捕獲InterruptedException發(fā)現(xiàn)了它,則最合理的做法是讓該線程完成,例如:
class Cleaner implements Runnable, AutoCloseable {private final Thread cleanerThread;Cleaner() {cleanerThread = new Thread(this, "Cleaner");cleanerThread.start();}@Overridepublic void run() {try {while (true) {cleanUp();TimeUnit.SECONDS.sleep(1);}} catch (InterruptedException ignored) {log.debug("Interrupted, closing");}}//... @Overridepublic void close() {cleanerThread.interrupt();} }注意, try-catch塊現(xiàn)在圍繞while循環(huán)。 這樣,如果sleep()拋出InterruptedException ,我們將跳出循環(huán)。 您可能會(huì)爭(zhēng)辯說,我們應(yīng)該記錄InterruptedException的堆棧跟蹤。 這取決于情況,因?yàn)樵谶@種情況下中斷線程是我們真正期望的,而不是失敗。 但這取決于你。 最重要的是,如果sleep()被另一個(gè)線程中斷,我們將很快完全脫離run() 。 如果您非常小心,您可能會(huì)問,如果線程在cleanUp()方法中而不是在睡眠時(shí)中斷線程,會(huì)發(fā)生什么情況? 通常,您會(huì)遇到這樣的手動(dòng)標(biāo)記:
private volatile boolean stop = false;@Override public void run() {while (!stop) {cleanUp();TimeUnit.SECONDS.sleep(1);} }@Override public void close() {stop = true; }但是請(qǐng)注意, stop標(biāo)志(必須是volatile !)不會(huì)中斷阻塞操作,我們必須等到sleep()完成。 另一方面,有人可能會(huì)爭(zhēng)辯說,顯式flag可以更好地控制我們,因?yàn)槲覀兛梢噪S時(shí)監(jiān)視其值。 事實(shí)證明,線程中斷的工作方式相同。 如果有人在執(zhí)行非阻塞計(jì)算時(shí)中斷了線程(例如在cleanUp()內(nèi)部),則不會(huì)立即中斷此類計(jì)算。 但是,線程被標(biāo)記為已中斷,并且隨后的所有阻塞操作(例如sleep() )都將立即立即拋出InterruptedException因此我們不會(huì)丟失該信號(hào)。
如果我們編寫仍想利用線程中斷功能的非阻塞線程,我們也可以利用這一事實(shí)。 不必依賴于InterruptedException我們只需定期檢查Thread.isInterrupted() :
public void run() {while (Thread.currentThread().isInterrupted()) {someHeavyComputations();} }在上方,如果有人中斷了我們的線程,則在someHeavyComputations()返回時(shí)我們將立即放棄計(jì)算。 如果它運(yùn)行了兩個(gè)長(zhǎng)時(shí)間或無限期,我們將永遠(yuǎn)不會(huì)發(fā)現(xiàn)中斷標(biāo)志。 有趣的是, interrupted標(biāo)志不是一次性的 。 我們可以調(diào)用Thread.interrupted()而不是isInterrupted() ,這將重置interrupted標(biāo)志并且我們可以繼續(xù)。 有時(shí)您可能想忽略中斷標(biāo)志并繼續(xù)運(yùn)行。 在這種情況下, interrupted()可能會(huì)派上用場(chǎng)。 順便說一句,我(不精確地)將“吸氣劑”稱為“ Heisengetters ”,它改變了被觀察物體的狀態(tài) 。
注意
如果您是老派程序員,您可能會(huì)想起Thread.stop()方法,該方法已被棄用10年了 。 在Java 8中,有計(jì)劃“取消實(shí)現(xiàn)它” ,但在1.8u5中它仍然存在。 但是,不要使用它,而是使用Thread.stop()將任何代碼重構(gòu)為Thread.interrupt() 。
番石榴的
您很少會(huì)完全忽略InterruptedException 。 在這種情況下,請(qǐng)查看番石榴的《 Uninterruptibles 。 它具有許多實(shí)用方法,如sleepUninterruptibly()或awaitUninterruptibly(CountDownLatch) 。 只是要小心他們。 我知道他們沒有聲明InterruptedException (可能很少),但是它們也完全防止了當(dāng)前線程的中斷–這是非常不尋常的。
摘要
到現(xiàn)在為止,我希望您對(duì)為什么某些方法引發(fā)InterruptedException有所了解。 主要的收獲是:
- 捕獲的InterruptedException應(yīng)該得到正確處理-大多數(shù)情況下,這意味著完全脫離當(dāng)前任務(wù)/循環(huán)/線程
- 吞下InterruptedException很少是一個(gè)好主意
- 如果線程不在阻塞調(diào)用中而被中斷,請(qǐng)使用isInterrupted() 。 當(dāng)線程已經(jīng)被中斷時(shí)也進(jìn)入阻塞方法應(yīng)該立即拋出InterruptedException 。
翻譯自: https://www.javacodegeeks.com/2014/06/interruptedexception-and-interrupting-threads-explained.html
總結(jié)
以上是生活随笔為你收集整理的InterruptedException和中断线程的说明的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Sonos 发布 Move 2 户外音响
- 下一篇: 联发科:3纳米制程芯片已成功流片 预计2