在互联网上的多篇文章中,建议不要吞咽InterruptedException
。当我要重用同一线程时,用这样的线程池执行程序来执行此操作更有意义。
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(() -> {
printNumbers(); // first call
printNumbers(); // second call
});
Thread.sleep(3_000);
executor.shutdownNow(); // will interrupt the task
executor.awaitTermination(3, TimeUnit.SECONDS);
}
private static void printNumbers() {
for (int i = 0; i < 10; i++) {
System.out.print(i);
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // preserve interruption status
break;
}
}
}
上面DZone中的代码示例。
但是在每次创建新线程的情况下,
Object LOCK = new Object();
public void doSomeJob() {
myThread = new Thread(new Runnable() {
public void run() {
try {
synchronized(LOCK) {
System.out.println("Inside run");
LOCK.wait();
}
} catch(InterruptedException ignored){}
}
}
}
我还需要打{{1}}吗?这有意义吗?
好的参考文献:
https://codepumpkin.com/interrupt-interrupted-isinterrupted-java-multithreading/
http://michaelscharf.blogspot.com/2006/09/dont-swallow-interruptedexception-call.html
答案 0 :(得分:3)
如果您的锁来自java.util.concurrent.locks.Lock
且可中断(使用.lockInterruptibly()
),则中断过程确实有意义,因此可能会中断和取消所有操作。
阅读documentation中的Implementation Considerations
章。
但是,如果您的锁是non-interruptible
(使用.lock()
),则将没有意义,因为您将无法中断该锁。
在您的情况下,您正在使用wait()
,该中断可按照here的书写方式中断,并且会抛出InterruptedException
。
答案 1 :(得分:3)
我将根据Brian Goetz伟大著作Concurrency in Practice的 7.1.2 部分给出答案。
在第一个示例中,您使用ExecutorService
。 ExecutorService
管理它自己的线程。您不是这些 Threads 的所有者,所以您不知道中断对他们意味着什么(例如, ThreadPool 可能会选择杀死那些中断并创建新的)。这就是为什么在向该池提交可取消任务时应保留中断状态的原因。此引用适用于这种情况:
任务不会在其拥有的线程中执行,而是借用诸如线程池之类的服务所拥有的线程。编码 不拥有线程(对于线程池,线程池实现之外的任何代码)应谨慎 保留中断状态,以便拥有代码最终可以对其执行操作,即使“ guest”代码对 以及中断。 (如果您要为某人提供住房,则不要丢掉他们不在时收到的邮件-保存并让他们回来后再处理,即使您确实阅读了他们的杂志也是如此。)
在第二种情况下,您将手动管理 Thread 的实例。因此,您是它的所有者。因此,您可以决定对该线程 意味着什么中断,并且如果不想应用任何 Thread中断,则不必保留第二种情况下的 Interruption Status 。政策:
您不应该做的就是吞下
InterruptedException
并在catch块中不执行任何操作,除非您的代码实际上为线程实现了中断策略
还请注意,线程中断策略与任务取消策略不同:
ThreadPool
可能会杀死被中断的线程并创建一个新线程)。它是由线程的所有者定义的。InterruptedException
的方法,则很容易实现。或者,您可以通过调用Thread::isInterrupted
(例如,在循环中)来检查线程的中断标志。任务的实施者选择处理方式。此外,您不应对线程中断策略做任何假设(如果您不是线程所有者)。这就是为什么保留中断状态或重新抛出InterruptedException
被认为是一种好习惯的原因。
答案 2 :(得分:2)
您问题中DZone链接https://dzone.com/articles/understanding-thread-interruption-in-java中的解释非常详细。 Thread.currentThread().interrupt();
会返回中断的异常状态,该状态之前已通过阻塞方法(sleep
)清除。这样做是为了确保第二个循环也被中断(它将捕获异常,因为它在同一线程上)。
在我结束之前,我想强调一下关于 阻止代码时线程的中断状态会如何 通过引发InterruptedException来响应中断。我离开了 直到现在才详细说明,以避免混淆。
在阻止代码引发InterruptedException之前,它标记了 中断状态为假。因此,当处理 InterruptedException完成后,您还应该保留 通过调用Thread.currentThread()。interrupt()中断状态。
让我们看看此信息如何适用于以下示例。在里面 提交给ExecutorService的任务printNumbers() 方法被调用两次。当任务被呼叫中断时 toshutdownNow(),对该方法的第一次调用提早完成,然后 执行到达第二个调用。中断由 主线程只有一次。中断被传达给 通过调用来第二次执行printNumber()方法 第一次执行时为Thread.currentThread()。interrupt()。因此 第二个执行也将在打印第一个之后的早期完成 数。不保留中断状态将导致 第二次执行该方法以完全运行9秒钟。
在何处使用Thread.currentThread().interrupt();
取决于您的代码,第二个示例并不完整,无法理解它的必要性。