2

我正在使用以下测试代码测试 InterruptedException:

Runnable runMe = new Runnable() {
    @Override
    public void run() {
        for(int i=0; i<6; i++) {
            System.out.println("i = "+i);
            if(i==3) {
                System.out.println("i==3, Thread = " 
                +Thread.currentThread().getId());
                //I invoke interrupt() on the working thread.
                Thread.currentThread().interrupt();
                try {
                    Thread.currentThread().join();
                } catch (InterruptedException e) {
                    //I caught InterruptedException
                    System.out.println(Thread.currentThread().getId() 
                    + " is interrupted!");
                    Thread.currentThread().interrupt();
                }
            }
        }
    }   
};          
Thread workingThread = new Thread(runMe);
workingThread.start();
try {
    workingThread.join();
} catch (InterruptedException e) {
    //Swallow
}
//the following log shows me workingThread.isInterrupted() is false, why?
System.out.println("workingThread(" 
+ workingThread.getId()+") interrupted ? " 
+ workingThread.isInterrupted());

run(),我interrupt()当前的工作线程,并抓住了一个InterruptedException.

在主线程中,我的最后一行代码是System.out.println(...)打印出工作线程的中断状态的代码。既然我陷入InterruptedExceptionrun(),我虽然应该得到正确的信息workingThread.isInterrupted()得到了错误的信息,为什么?

4

2 回答 2

4

Oracle 的Java 并发教程说(我的重点补充):

中断状态标志

中断机制是使用称为中断状态的内部标志来实现的。调用 Thread.interrupt 设置此标志。当线程通过调用静态方法 Thread.interrupted 检查中断时,中断状态被清除。一个线程用来查询另一个线程的中断状态的非静态 isInterrupted 方法不会改变中断状态标志。

按照惯例,任何通过抛出 InterruptedException 退出的方法都会在这样做时清除中断状态。然而,中断状态总是有可能被另一个线程调用中断立即再次设置。

您看到的是线程被中断,退出的方法是连接(实际上连接是通过调用 Object.wait 实现的,所以我希望堆栈跟踪会显示等待是引发异常的方法),并且标志被清除,就像教程说的那样。

由异常处理程序决定是否应该再次设置线程的中断状态标志。除非对处理程序进行编码以执行不同的操作,否则默认假设是已处理异常并且不再需要设置标志。

Thread#interrupt的API 文档与此一致:

如果该线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法或 join()、join(long)、join(long, int) 时被阻塞, sleep(long), or sleep(long, int), 这个类的方法,那么它的中断状态会被清除并且会收到一个InterruptedException。

我有一个答案,更详细地说明了为什么这里会以这种方式设计中断。

于 2014-10-17T17:20:07.167 回答
0
Runnable runMe = new Runnable() {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("i = " + i);
            if (i == 3) {
                System.out.println("i==3, Thread = "
                        + Thread.currentThread().getId());
                //I invoke interrupt() on the working thread.
                Thread.currentThread().interrupt();
                try {
                    Thread.currentThread().join();
                } catch (InterruptedException e) {
                    //I caught InterruptedException
                    System.out.println(Thread.currentThread().getId()
                            + " is interrupted!");
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
};
Thread workingThread = new Thread(runMe);
workingThread.start();
Thread.sleep(1);
// output true, because child thread not deaded
System.out.println("workingThread("
        + workingThread.getId() + ") interrupted ? "
        + workingThread.isInterrupted());
于 2020-10-15T17:02:10.547 回答