2013-03-17 80 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

相关问题