2013-03-17 86 views
-1

假設下面的代碼是通過調試器執行的,以便我們可以預測執行的順序。爲什麼task1線程不會中斷

  • t1 - 這裏task1開始處理一些長時間的任務。
  • t2 --- task2被阻止@同步語句,因爲task1持有鎖。
  • t3 - task2被中斷但錯過了,因爲task2正在使用內部鎖,因此不能被中斷@ synchronized。 (Renenterant.lockInterruptible()會拋出InterruptedExecption)。
  • t4 --- task1中斷。然而,儘管在try catch塊中執行了複雜的任務,但InterruptedExeption從未拋出。這是爲什麼 ?

代碼:

public class TestInteruptibility { 
    public static Object lock = new Object(); 
    public static boolean spin = true; 

    public static void main(String[] args) { 
     Thread task1 = new Thread(new Task(), "Task1"); 
     Thread task2 = new Thread(new Task(), "Task2"); 
     Thread notifier1 = new Thread(new Notifier(), "Notifier1"); 
     task1.start(); 
     task2.start(); 
     task2.interrupt(); 
     task1.interrupt(); 
     notifier1.start(); 
    } 
} 

class Task implements Runnable { 
    public void run() { 
     synchronized (TestInteruptibility.lock) { 
      System.out.println("Performing Long Task"); 
      try { 
       while (TestInteruptibility.spin) { 
       } 
       System.out.println("Finsihed Performing Long Task"); 
       TestInteruptibility.lock.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
       System.out.println("I got interrupted while i was waiting @ wait()"); 
      } 
      System.out.println("Ending Task"); 
     } 
    } 
} 

class Notifier implements Runnable { 
    public void run() { 
     synchronized (TestInteruptibility.lock) { 
      System.out.println("Performing notification"); 
      TestInteruptibility.lock.notify(); 
      System.out.println("Ending notification"); 
     } 
    } 
} 
+0

'spin'永遠不會是假的,循環永遠不會終止,你永遠不會看到「Finsihed [sic]正在執行長時間任務」。 – erickson 2013-03-17 06:45:26

回答

3

基本上,interrupt()所做的就是在Thread對象中設置一個標誌。你需要用isInterrupted()來檢查它。然後你可以處理這個中斷信號。在這種情況下它不會拋出InterruptedException

此外,它可能會導致一些方法,例如,Thread.sleep(),Object.wait(),立即返回並拋出InterruptedException。在這種情況下你可以得到和InterruptedException

Java併發實踐,7.1.1。中斷

A good way to think about interruption is that it does not actually interrupt a running thread; it just requests that the thread interrupt itself at the next convenient opportunity. (These opportunities are called cancellation points.) Some methods, such as wait, sleep, and join, take such requests seriously, throwing an exception when they receive an interrupt request or encounter an already set interrupt status upon entry. Well behaved methods may totally ignore such requests so long as they leave the interruption request in place so that calling code can do something with it. Poorly behaved methods swallow the interrupt request, thus denying code further up the call stack the opportunity to act on it.

在你上面的代碼中,你是不是在等待/睡眠。所以你必須檢查isInterrupted()並在while循環中自己處理中斷信號。

while (TestInteruptibility.spin) { 
    if (Thread.currentThread().isInterrupted()) { 
     break; 
    } 
} 

參考文獻:

  1. why interrupt() not work as expected and how does it work
  2. What does java.lang.Thread.interrupt() do?
2

你有一個繁忙的while循環,持有該鎖(和永遠不會結束,除非你改變旋轉的價值的地方)。我認爲task1仍在循環中,因此它不會注意到中斷。 Task2無法獲取鎖,因此它會阻止。

任務執行的方式,它只能在等待命令執行期間中斷,這個命令在循環之後執行。

順便說一句:如果你在不同的線程中使用旋轉數據成員,那麼它應該被聲明爲volatile。由於類似的線程安全原因,鎖應聲明爲最終。

0

當你調用方法interrupt()的結果取決於該線目前正在做。如果它被一些可中斷的方法(如Object.wait())阻塞,那麼它會立即中斷,這意味着InterruptedException將被拋出線程。如果線程未被阻塞,但正在進行一些計算,或者它在一些不可中斷的方法(如InputStream.read())上阻塞,則不會引發InterruptedException,而是在線程上設置interrupted標誌。這個標誌將導致下一次線程調用InterruptedException一些可中斷的方法,但不是現在。

在你的情況螺紋task1task2無限空循環的旋轉,因此不會阻塞任何中斷的方法,所以當你再調用interrupt(),沒有InterruptedException拋出的線程內,但interrupted標誌剛剛成立。你或許應該改變你的任務的代碼看起來像這樣:

while (TestInteruptibility.spin && !Thread.interrupted()) { 
} 

,那麼你只要會從循環退出正如有人會叫interrupt的任務線程。

+0

該條件將是一個很好的測試。另外,'spin'必須被聲明爲'volatile'字段,以保證可視性。 – erickson 2013-03-17 07:06:57

+0

我無法使用ReentrantLock.lockInterruptibility()修復我的問題, – deepujain 2013-03-17 08:49:28

相關問題