Java 线程 InterruptExceptioon 处理仅在某些情况下停止执行更多代码
Java thread InterruptExceptioon handling stopped further code from being executed only in some situation
以下简短示例代码说明了我无法解释的行为
ConcurrentLinkedDeque<Double> testQueue = new ConcurrentLinkedDeque<>();
Thread t = new Thread(() -> {
long cnt = 0;
try {
while(!Thread.currentThread().isInterrupted()) {
testQueue.add(Math.random());
cnt++;
try {
Thread.sleep(100);
}catch (Exception e) {
System.out.println(String.format("inner interrupted inserted %d record", cnt));
}
}
} catch (Exception e) {
System.out.println(String.format("interrupted inserted %d record", cnt));
}
System.out.println(String.format("inserted %d record", cnt));
});
如果我调用t.interrupt()
来中断线程
预期的行为是 2 行打印内容:
inner interrupted inserted %d record
inserted %d record
其中 %d 被替换为相应的值。
但实际结果是
inner interrupted inserted %d record
如果我们删除线程的内部捕获
ConcurrentLinkedDeque<Double> testQueue = new ConcurrentLinkedDeque<>();
Thread t = new Thread(() -> {
long cnt = 0;
try {
while(!Thread.currentThread().isInterrupted()) {
testQueue.add(Math.random());
cnt++;
Thread.sleep(100);
}
} catch (Exception e) {
System.out.println(String.format("interrupted inserted %d record", cnt));
}
System.out.println(String.format("inserted %d record", cnt));
});
然后我们得到输出
interrupted inserted %d record
inserted %d record
正如预期的那样,现在外层捕获正在捕获 InterruptException
但是,如果我将 break 放在第一个代码示例的最内层 catch 中,如下所示:
ConcurrentLinkedDeque<Double> testQueue = new ConcurrentLinkedDeque<>();
Thread t = new Thread(() -> {
long cnt = 0;
try {
while(!Thread.currentThread().isInterrupted()) {
testQueue.add(Math.random());
cnt++;
try {
Thread.sleep(100);
}catch (Exception e) {
System.out.println(String.format("inner interrupted inserted %d record", cnt));
break; //this one
}
}
} catch (Exception e) {
System.out.println(String.format("interrupted inserted %d record", cnt));
}
System.out.println(String.format("inserted %d record", cnt));
});
产生了预期的行为。
为什么 catch 块的放置会产生这样的差异?
请参阅 Thread#interrupt
的文档:
If this thread is blocked in an invocation of [...] sleep(long), or sleep(long, int), [...], then its interrupt status will be cleared and it will receive an InterruptedException.
If none of the previous conditions hold then this thread's interrupt status will be set.
这意味着在您的示例中 Thread#sleep
抛出异常 XOR Thread.currentThread().isInterrupted()
给您 true。
因此,在您的第一个示例中,您捕获了异常,在无限循环中执行打印和 enter/stay,因为 Thread.currentThread().isInterrupted()
始终是 false
。
在你的第二个例子中,try-catch 没有嵌套在循环中,所以两个打印都发生并且线程按预期终止。
在您的第三个示例中,您只是显式地退出了循环。
仅供参考: 你不需要写 System.out.println(String.format(...))
。有System.out.printf
,但别忘了\n
.
以下简短示例代码说明了我无法解释的行为
ConcurrentLinkedDeque<Double> testQueue = new ConcurrentLinkedDeque<>();
Thread t = new Thread(() -> {
long cnt = 0;
try {
while(!Thread.currentThread().isInterrupted()) {
testQueue.add(Math.random());
cnt++;
try {
Thread.sleep(100);
}catch (Exception e) {
System.out.println(String.format("inner interrupted inserted %d record", cnt));
}
}
} catch (Exception e) {
System.out.println(String.format("interrupted inserted %d record", cnt));
}
System.out.println(String.format("inserted %d record", cnt));
});
如果我调用t.interrupt()
来中断线程
预期的行为是 2 行打印内容:
inner interrupted inserted %d record
inserted %d record
其中 %d 被替换为相应的值。
但实际结果是
inner interrupted inserted %d record
如果我们删除线程的内部捕获
ConcurrentLinkedDeque<Double> testQueue = new ConcurrentLinkedDeque<>();
Thread t = new Thread(() -> {
long cnt = 0;
try {
while(!Thread.currentThread().isInterrupted()) {
testQueue.add(Math.random());
cnt++;
Thread.sleep(100);
}
} catch (Exception e) {
System.out.println(String.format("interrupted inserted %d record", cnt));
}
System.out.println(String.format("inserted %d record", cnt));
});
然后我们得到输出
interrupted inserted %d record
inserted %d record
正如预期的那样,现在外层捕获正在捕获 InterruptException
但是,如果我将 break 放在第一个代码示例的最内层 catch 中,如下所示:
ConcurrentLinkedDeque<Double> testQueue = new ConcurrentLinkedDeque<>();
Thread t = new Thread(() -> {
long cnt = 0;
try {
while(!Thread.currentThread().isInterrupted()) {
testQueue.add(Math.random());
cnt++;
try {
Thread.sleep(100);
}catch (Exception e) {
System.out.println(String.format("inner interrupted inserted %d record", cnt));
break; //this one
}
}
} catch (Exception e) {
System.out.println(String.format("interrupted inserted %d record", cnt));
}
System.out.println(String.format("inserted %d record", cnt));
});
产生了预期的行为。
为什么 catch 块的放置会产生这样的差异?
请参阅 Thread#interrupt
的文档:
If this thread is blocked in an invocation of [...] sleep(long), or sleep(long, int), [...], then its interrupt status will be cleared and it will receive an InterruptedException.
If none of the previous conditions hold then this thread's interrupt status will be set.
这意味着在您的示例中 Thread#sleep
抛出异常 XOR Thread.currentThread().isInterrupted()
给您 true。
因此,在您的第一个示例中,您捕获了异常,在无限循环中执行打印和 enter/stay,因为 Thread.currentThread().isInterrupted()
始终是 false
。
在你的第二个例子中,try-catch 没有嵌套在循环中,所以两个打印都发生并且线程按预期终止。
在您的第三个示例中,您只是显式地退出了循环。
仅供参考: 你不需要写 System.out.println(String.format(...))
。有System.out.printf
,但别忘了\n
.