什么时候调用Thread.currentThread()。interrupt()以及什么时候不调用?

时间:2019-08-20 14:04:32

标签: java multithreading interrupt

在互联网上的多篇文章中,建议不要吞咽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

3 个答案:

答案 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 部分给出答案。

在第一个示例中,您使用ExecutorServiceExecutorService管理它自己的线程。您不是这些 Threads 的所有者,所以您不知道中断对他们意味着什么(例如, ThreadPool 可能会选择杀死那些中断并创建新的)。这就是为什么在向该池提交可取消任务时应保留中断状态的原因。此引用适用于这种情况:

  

任务不会在其拥有的线程中执行,而是借用诸如线程池之类的服务所拥有的线程。编码   不拥有线程(对于线程池,线程池实现之外的任何代码)应谨慎   保留中断状态,以便拥有代码最终可以对其执行操作,即使“ guest”代码对   以及中断。 (如果您要为某人提供住房,则不要丢掉他们不在时收到的邮件-保存并让他们回来后再处理,即使您确实阅读了他们的杂志也是如此。)

在第二种情况下,您将手动管理 Thread 的实例。因此,您是它的所有者。因此,您可以决定对该线程 意味着什么中断,并且如果不想应用任何 Thread中断,则不必保留第二种情况下的 Interruption Status 。政策

  

您不应该做的就是吞下InterruptedException并在catch块中不执行任何操作,除非您的代码实际上为线程实现了中断策略

还请注意,线程中断策略任务取消策略不同:

  1. 线程中断策略-定义线程如何对中断做出反应(例如ThreadPool可能会杀死被中断的线程并创建一个新线程)。它是由线程的所有者定义的。
  2. 任务取消政策-定义任务对取消的反应。取消通常会中断执行。执行任务的人选择任务是否响应中断。如果您的任务调用抛出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();取决于您的代码,第二个示例并不完整,无法理解它的必要性。