在Java中中断循环线程

在Java中中断循环线程,java,multithreading,interrupted-exception,interruption,Java,Multithreading,Interrupted Exception,Interruption,我试图理解线程在Java中是如何工作的,目前正在研究如何实现可以取消的循环线程。代码如下: public static void main(String[] args) throws Exception { Thread t = new Thread() { @Override public void run() { System.out.println("THREAD: started"); try {

我试图理解线程在Java中是如何工作的,目前正在研究如何实现可以取消的循环线程。代码如下:

public static void main(String[] args) throws Exception {
    Thread t = new Thread() {
        @Override
        public void run() {
            System.out.println("THREAD: started");
            try {
                while(!isInterrupted()) {
                    System.out.printf("THREAD: working...\n");
                    Thread.sleep(100);
                }
            } catch(InterruptedException e) {
                // we're interrupted on Thread.sleep(), ok

                // EDIT
                interrupt();

            } finally {
                // we've either finished normally
                // or got an InterruptedException on call to Thread.sleep()
                // or finished because of isInterrupted() flag

                // clean-up and we're done
                System.out.println("THREAD: done");
            }               
        }
    };

    t.start();
    Thread.sleep(500);
    System.out.println("CALLER: asking to stop");
    t.interrupt();
    t.join();
    System.out.println("CALLER: thread finished");
}
我创建的线程迟早会被中断。因此,我检查isInterrupted()标志以决定是否需要继续并捕获
InterruptedException
,以处理处于等待操作中的情况(
sleep
join
wait

我想澄清的是:

  • 对这种任务使用中断机制可以吗?(与具有
    易失性布尔值相比应停止
  • 这个解决方案正确吗
  • 我吞下中断异常是正常的吗?我对有人让我的线程中断的那段代码不感兴趣
  • 有没有更短的方法来解决这个问题?(要点是具有“无限”循环)
  • 编辑 添加了对
    InterruptedException
    捕获中的
    interrupt()
    的调用。我回答的是第3个问题:

    基本上,问题是:中断异常有什么用途?它告诉你停止阻塞(如睡觉),早点回来

    有两种处理中断异常的方法:

    • 重新旋转它,使线程保持中断状态
    • 再次设置
      Thread.currentThread.interrupt()
      ,然后执行清理工作。这样,您可以确保线程中另一个开始休眠的方法将再次抛出
    简单地吞下一个
    InterruptedException
    并不是一个好主意,因为这样一个中断的目的是最终终止。但你只是被要求打断,所以你还有时间清理

    在这种情况下,这可能是我自己的“过度反应”,但通常这样的代码要复杂得多,您如何知道,该线程中的一些后续代码不会再次调用阻塞方法

    编辑

    否则我认为你做的很好。不过,对我来说有点惊讶,因为我从来没有看到任何人在自己的代码中真正这么做

    下面是一篇有趣的文章,解释了为什么会这样:

  • 是的,很好。您应该记录线程/可运行线程必须如何停止。您可以在可运行的实现中添加一个专用的stop方法来封装停止机制。要么使用中断,要么使用专用布尔值,或者两者都使用
  • 是的,但良好的做法是在捕获InterruptedException时恢复中断状态:
    Thread.currentThread().interrupt()
  • 否,您应该恢复中断状态
  • 我不知道
  • 1) 根据JavaConcurrency in Practice一书,示例中的方法比使用volatile标志(这是多余的,因为您已经有了中断标志)更可取。这就是InterruptedException的用途

    2) 对

    3) 只要恢复中断标志状态,就可以消除异常。异常并不表示错误,因此不会丢失任何信息,它纯粹是一种传递控制的方法。(恢复中断标志状态对于具有嵌套控制结构的情况非常重要,每个嵌套控制结构都需要通知线程正在取消,对于像您这样的简单示例,这是一种很好的形式,但如果缺少它,则不会造成任何影响。)


    4) 不

    可以使用中断,但要好好使用它们。您必须在catch中重新抛出
    Thread.currentThread().interrupt()
    。下面是一段代码,说明了原因:

    public class MyThread extends Thread {
        private static boolean correct = true;
    
        @Override
        public void run() {
            while (true) {
                // Do Something 1
                for (int i = 0; i < 10; i++) { // combined loop
                    // Do Something 2
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException ex) {
                        if (correct)
                            Thread.currentThread().interrupt(); // reinterrupting
                        System.out.println("First Catch");
                        break; // for
                    }
                }
                try {
                    // Do Something 3
                    System.out.print("before sleep, ");
                    Thread.sleep(1000);
                    System.out.print("After sleep, ");
                } catch (InterruptedException ex) {
                    if (correct)
                        Thread.currentThread().interrupt();
                    System.out.println("Second catch");
                    break; // while
                }
            }
            System.out.println("Thread closing");
        }
    
        private static void test() throws InterruptedException {
            Thread t = new MyThread();
            t.start();
            Thread.sleep(2500);
            t.interrupt();
            t.join();
            System.out.println("End of Thread");
        }
    
        public static void main(String[] args)
                throws InterruptedException {
            test();
            correct = false; // test "bad" way
            test();
        }
    }
    

    好吧,我相信重新引用不是一种情况,因为我不能从线程的
    run()
    中抛出。是否应调用中断()
    ?isInterrupted不会重置中断标志。如何在不中断的情况下阻止线程长时间等待或休眠?没关系,但最好不要扩展线程,因为它没有扩展其功能。实现一个可运行线程,供标准线程使用。
    public class Mythread extends Thread {
        private InputStream in;
    
        public Mythread(InputStream in) {
            this.in = in;
        }
    
        @Override
        public void interrupt() {
            super.interrupt();
            try {
                in.close(); // Close stream if case interruption didn't work
            } catch (IOException e) {}
        }
    
        @Override
        public void run() {
            try {
                System.out.println("Before read");
                in.read();
                System.out.println("After read");
            } catch (InterruptedIOException e) { // Interruption correctly handled
                Thread.currentThread().interrupt();
                System.out.println("Interrupted with InterruptedIOException");
            } catch (IOException e) {
                if (!isInterrupted()) { // Exception not coming from Interruption
                    e.printStackTrace();
                } else { // Thread interrupted but InterruptedIOException wasn't handled for this stream
                    System.out.println("Interrupted");
                }
            }
        }
    
        public static void test1() // Test with socket
                throws IOException, InterruptedException {
            ServerSocket ss = new ServerSocket(4444);
            Socket socket = new Socket("localhost", 4444);
            Thread t = new Mythread(socket.getInputStream());
            t.start();
            Thread.sleep(1000);
            t.interrupt();
            t.join();
        }
    
        public static void test2() // Test with PipedOutputStream
                throws IOException, InterruptedException { 
            PipedInputStream in = new PipedInputStream(new PipedOutputStream());
            Thread t = new Mythread(in);
            t.start();
            Thread.sleep(1000);
            t.interrupt();
            t.join();
        }
    
        public static void main(String[] args) throws IOException, InterruptedException {
            test1();
            test2();
        }
    }