2017-05-06 24 views
1

如果我寫下如下代碼,我們不能中斷或終止線程。它也不會拋出InterruptedException。爲什麼InterruptedException僅從像sleep()和wait()這樣的阻塞方法中拋出異常?

Thread loop = new Thread(
    new Runnable() { 
    @Override 
    public void run() { 
     while (true) { 
     } 
    } 
    } 
); 
loop.start(); 
loop.interrupt(); 

要中斷這個線程,我需要如下修改我的代碼:

Thread loop = new Thread(
    new Runnable() { 
    @Override 
    public void run() { 
     while (true) { 
     if (Thread.interrupted()) { 
      break; 
     } 
     // Continue to do nothing 
     } 
    } 
    } 
); 
loop.start(); 
loop.interrupt(); 

我的問題是,

  1. 爲什麼Java的設計以這樣的方式,InterruptedException的只有在像sleep()和wait()這樣的阻塞方法的情況下才會被拋出。

  2. 爲什麼在普通代碼中,我們需要像上面的代碼片段那樣手動處理?爲什麼Java不會拋出InterruptedException,只要我們通過設置中斷標誌true爲interrupt()方法?

我已經閱讀了很多關於InterruptedException的博客和文章,但還沒有找到任何有說服力的答案。

編輯

發現好文章InterruptedException的:爪哇 http://codepumpkin.com/interruptedexception-java-multithreading/

+6

如果在正常執行過程中代碼可能被中斷,那麼它將不得不在每一行代碼之間進行檢查,並且會很慢。此外,一些代碼要求它運行到完成,否則會產生不可預知的錯誤(例如不關閉資源)。 – 4castle

+1

這基本上是停止使用的stop()方法所做的。你可以閱讀它在javadoc中被棄用的原因。但是4castle解釋得非常好。 –

+1

Java中斷是*合作*。一個線程可以要求另一個線程停止正在進行的操作,但是不需要其他線程立即執行或者甚至執行任何操作。 –

回答

3

1)爲什麼Java的設計以這樣的方式,InterruptedException異常被拋出僅在阻止類似睡眠的方法的情況下,()和wait()。

thread.interrupt()整點是它是合作的。一個線程被中斷,但它必須使用Thread.currentThread().isInterrupted()檢查中斷標誌,以便它可以正確管理它自己的終止,並在必要時清理共享對象,鎖定,最終塊等。

要引用tutorial on the subject,強調我的。

中斷表示線程應該停止它正在執行的操作並執行其他操作。它是直到程序員決定一個線程如何響應中斷,但它是非常常見的線程終止。

InterruptedException的方法是正在等待的鎖和其他條件的人。這些表示它們被中斷,因此線程在終止之前可以自行清理。

2)爲什麼在普通代碼中,我們需要手動處理這個問題,就像我上面的代碼片段一樣?爲什麼每當我們通過interrupt()方法設置中斷標誌爲true時,Java不會拋出InterruptedException?

的選擇將是有InterruptedException是它可能在任何時候被拋出,不管程序是否被期待它的RuntimeExceptionstop()和其他棄用的Thread方法的部分問題是它們傾向於違反各種語言結構,並可能使應用程序內存處於不良狀態。這裏的more details about that

如果是RuntimeExceptionInterruptedException也可以這樣說。你可以想象如果一個線程正在改變一個共享對象,然後在中途拋出一個意外的RuntimeException或完全停止。正在更新的共享對象很容易處於無效狀態。

if (Thread.interrupted()) { 

這不叫,因爲它清除線程這是壞的圖案中斷標誌正確的方法。請使用以下命令:

if (Thread.currentThread().isInterrupted()) { 

這保留了其應儘可能做到中斷標誌。此外,當InterruptedException被拋出,也清除中斷標誌。這就是爲什麼這是一個很好的模式:

try { 
    ... 
} catch (InterruptedException ie) { 
    // re-interrupt the thread to propagate the interrupt flag 
    Thread.currentThread().interrupt(); 
    // handle the interrupt here by probably quitting the thread 
} 

圖書館「吞下」中斷標誌有很多問題。即使你的代碼很小,它可能會被複制到一個更大的塊中,所以你總是可以將中斷標誌恢復爲一個好的模式。

+1

謝謝格雷..瞭解.. !! –

+1

回覆:「另外,當你捕獲'InterruptedException'也清除中斷標誌」:這不太正確。相反,只是拋出*'InterruptedException'的JDK方法在這樣做之前都清除中斷標誌。但是如果標誌被設置了,無論出於何種原因,當你捕捉到'InterruptedException'時,那麼捕捉那個異常的行爲將不會清除該標誌。見例如http://ideone.com/H4wzrA。 (但是你的建議模式是正確的。) – ruakh

+0

好的修正@ruakh。 – Gray

1

早期版本中使用的是能夠殺死線程,而是試圖支持多種操作系統時很快就成了問題。 有很多不同的方法操作系統實現具有非常不同功能的線程。 在中途停止線程被認爲是不安全的,可能導致應用程序的其他部分發生意外行爲,如死鎖。

更多細節在這裏: https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

+2

感謝您對stop()方法的棄用和線程的殺死。 但它不是關於停止線程,它只是關於從所有者線程中斷子線程。我們總是可以採取預防措施來處理意外行爲。 我發現更令人信服的是上面的4castle的評論:「如果代碼在正常執行過程中可能被中斷,那麼它將不得不在每一行代碼之間進行檢查,並且會非常緩慢。」 任何方式謝謝。 Upvoting你的答案:) –

+0

*「我們總是可以採取預防措施來處理意外的行爲。」*真的嗎?告訴我,如果你無法確切地知道線程什麼時候(或哪裏)會結束,你將如何維持失敗的原子性? – scottb

+1

存在您的線程當前正在運行的編譯代碼。除非操作系統決定給另一個線程分配CPU時間,否則您的代碼無法在任何時候中斷。 因此,開發人員不必依靠操作系統在幕後進行這種操作,而是在方便的時候讓線程中斷。 這是一個妥協,因爲Java代碼能夠在許多不同的體系結構上運行,並且在線程方面的功能大不相同。 –

相關問題