为什么在catch InterruptException块中调用Thread.currentThread.interrupt()?


Answers:


160

这样做是为了保持状态

捕获InterruptException并吞下它时,实际上可以防止任何更高级别的方法/线程组注意到该中断。这可能会导致问题。

通过调用Thread.currentThread().interrupt(),您可以设置线程的中断标志,以便更高级别的中断处理程序将注意到它并可以适当地对其进行处理。

Java并发实践第7.1.3章:响应中断中对此进行了详细讨论。其规则是:

只有实现线程中断策略的代码才能吞下中断请求。通用任务和库代码绝不应吞咽中断请求。


15
文档它说,“按照惯例,任何方法,通过抛出一个退出InterruptedException 清除中断状态,当它这样做。我认为,这使答案更清晰的来讲,为什么你需要保存中断状态。
斯泰利奥斯Adamantidis

还值得注意的是,一旦您通过其他“传递机制”收到关于此状态的通知,则interrupt()调用是设置中断标志的唯一方法- InterruptedException并希望或不能将其重新抛出。
sevo

67

我认为此代码示例使事情变得更加清晰。完成工作的班级:

   public class InterruptedSleepingThread extends Thread {

        @Override
        public void run() {
            doAPseudoHeavyWeightJob();
        }

        private void doAPseudoHeavyWeightJob() {
            for (int i=0;i<Integer.MAX_VALUE;i++) {
                //You are kidding me
                System.out.println(i + " " + i*2);
                //Let me sleep <evil grin>
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Thread interrupted\n Exiting...");
                    break;
                }else {
                    sleepBabySleep();
                }
            }
        }

        /**
         *
         */
        protected void sleepBabySleep() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }

主类:

   public class InterruptedSleepingThreadMain {

        /**
         * @param args
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
            InterruptedSleepingThread thread = new InterruptedSleepingThread();
            thread.start();
            //Giving 10 seconds to finish the job.
            Thread.sleep(10000);
            //Let me interrupt
            thread.interrupt();
        }

    }

尝试调用中断而不将状态重新设置。


13
所以结论是
斯科特混合理论

3
谢谢。我现在明白您的意思了: repl.it/@djangofan/InterruptedThreadExample
djangofan '18年

20

注意:

http://download.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

如何停止等待较长时间(例如,输入)的线程?

为了使该技术起作用,至关重要的是任何捕获中断异常并且不准备处理该异常的方法都应立即重新声明该异常。我们说重新声明而不是重新抛出,因为并非总是可能重新抛出异常。如果未声明捕获InterruptedException的方法引发此(检查的)异常,则它应使用以下提示“重新中断自身”:

Thread.currentThread().interrupt();

这样可以确保Thread将尽快引发InterruptedException。


2

我认为这是一种不好的做法,或者至少有点冒险。通常,更高级别的方法不会执行阻塞操作,并且它们永远不会InterruptedException在那里看到。如果在执行中断操作的每个位置屏蔽它,您将永远无法获得它。

Thread.currentThread.interrupt()不会引发任何其他异常或以其他任何方式发出中断请求(例如interrupted,在线程的主循环中设置局部变量变量)的唯一理由是,您实际上无法对异常执行任何操作(如在finally块中)。

如果您想更好地了解Thread.currentThread.interrupt()电话的含义,请参阅PéterTörök的答案。


0

从Java Doc引用

如果此线程在调用wait(),join(),sleep(long)时被阻塞,则其中断状态将被清除,并且将收到InterruptedException。

如果此线程在I / O操作中被阻止,则将设置线程的中断状态,并且该线程将收到ClosedByInterruptException。

如果此线程在选择器中被阻塞,则将设置该线程的中断状态,并从选择操作中立即返回。

如果上述条件均不成立,则将设置该线程的中断状态。

因此,如果您在@Ajay George Answer的I / O操作或仅是sysout中更改了sleepBabySleep()方法,则不必将状态重新设置为停止程序。(顺便说一句,他们甚至没有抛出InterruptedException)

就像@PéterTörök所说的=>这样做是为了保持状态。(特别是对于将抛出InterruptedException的方法)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.