为什么task1线程没有被中断

时间:2013-03-17 06:35:50

标签: java concurrency

假设使用调试器执行以下代码,以便我们可以预测执行顺序。

  • t1 - 这里task1开始处理一些长任务。
  • t2 --- task2被阻止@ Syncronized语句因为task1持有锁定。
  • t3 - task2被中断,但是因为task2正在使用内部锁而被错过,因此无法中断@ synchronized。 (Renenterant.lockInterruptible()会抛出InterruptedExecption)。
  • t4 --- task1被打断了。然而,尽管在try catch块中执行了复杂的任务,但从未抛出InterruptedExecption。那是为什么?

代码:

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");
        }
    }
}

3 个答案:

答案 0 :(得分:3)

基本上,interrupt()的作用是在Thread对象中设置一个标志。您需要使用isInterrupted()进行检查。然后你可以处理这个中断信号。在这种情况下,它不会抛出InterruptedException

此外,它可能导致某些方法(例如Thread.sleep()Object.wait())立即返回并抛出InterruptedException。在这种情况下你可以得到InterruptedException

来自 Java Concurrency in Practice,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?

答案 1 :(得分:2)

你有一个忙碌的while循环,它持有锁(并且永远不会结束,除非你在某处更改spin的值)。我认为task1仍处于循环中,因此它没有注意到中断。 Task2无法获取锁定,因此它会阻止。

实现Task的方式,它只能在循环之后的wait命令中被中断。

BTW:如果你在不同的线程中使用自旋数据成员,那么它应该被声明为volatile。出于类似的线程安全原因,应将lock声明为final。

答案 2 :(得分:0)

当您调用方法interrupt()时,结果取决于此线程当前正在执行的操作。如果它在某些可中断的方法(例如Object.wait())上被阻塞,那么它将立即被中断,这意味着InterruptedException将被抛入线程内。如果线程没有被阻塞,但正在进行一些计算,或者它是某些不可中断的方法(例如InputStream.read()上的阻塞),则不会抛出InterruptedException,但是在线程上设置了interrupted标志代替。这个标志将导致InterruptedException下次线程调用某些可中断的方法,但现在不会。

在你的情况下,线程task1task2在无限空循环中旋转,因此不会在任何可中断的方法上被阻塞,所以当你打开interrupt()时,没有{{1在该线程中抛出,但InterruptedException标志刚刚设置。您可能应该将任务代码更改为:

interrupted

然后只要有人在任务线程上调用while (TestInteruptibility.spin && !Thread.interrupted ()) { } ,你就会退出循环。