引发InterruptedException时,java线程中断状态未清除
有人能解释一下为什么这个程序会打印多个“中断”语句吗
根据线程。睡眠javadoc
InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) throws Exception {
for (int z = 0; z < 100; z++) {
ExecutorService executor1 = Executors.newSingleThreadExecutor();
executor1.execute(new Runnable() {
@Override
public void run() {
ExecutorService executor2 = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executor2.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000 * 100);
} catch (InterruptedException e) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("interrupted");
}
}
}
});
}
executor2.shutdownNow();
try {
executor2.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
}
}
});
executor1.shutdown();
try {
executor1.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
}
}
}
}
# 1 楼答案
简而言之:
你看到这种行为是因为你有一个种族条件。有一个字段
ReentrantLock ThreadPoolExecutor::mainLock
。方法shutdownNow
受其保护,但启动工作线程不受保护要深入挖掘:
看看
ThreadPoolExecutor::execute(Runnable)
。以下是片段:现在,让我们来看看工人是如何开始的。以下是
runWorker
方法片段(我的一些评论):在这种情况下,关闭执行器并执行任务是一种快速的方式
更具体地说,工作线程在任务执行开始之前被中断,在工作线程被
ExecutorService::shutdownNow
方法中断之前,工作线程被中断,但在关闭启动之后被中断如果您运气不好,中断状态将由条件之前的
shutdownNow
方法更新是check,但是在对
Thread.sleep(1000 * 100);
的调用之后立即抛出(因为已经被中断)UPD:我在调用
Thread.sleep(1000 * 100);
之前插入了System.out.println(Thread.currentThread().isInterrupted());
,现在我无法重现该情况我猜现在在调用
Thread::sleep
之前,方法ExecutorService::shutdownNow
会中断所有线程注意:同样的行为可能还有其他原因,但从我运行的测试来看,这一个似乎最有可能
# 2 楼答案
这个答案是错误的(保持原样以便人们知道这个代码片段不是原因)
Executors.newFixedThreadPool()
方法返回一个ThreadPoolExecutor
如果你看一下
ThreadPoolExecutor.shutdownNow()
,你会发现它可能会中断工人两次所以一定是一些线程被中断了两次
当他们第一次被打扰时,他们会从睡眠状态中出来,抛出一个InterruptedException。但在他们这么做之后,他们又被打断了(在执行代码之前)
# 3 楼答案
来自doc
当您在
Thread.sleep(1000 * 100)
期间关闭executor服务并抛出InterruptedException
时,状态将被清除但是ThreadPoolExecutor通过
t.interrupt()
重新设置状态,因此您仍然可以获得状态以下是重置状态的代码: