中断Java中的循环线程

发布于 2024-11-29 08:01:10 字数 1625 浏览 6 评论 0原文

我正在尝试了解线程在 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加入等待)。

我想澄清的是:

  1. 这种任务使用中断机制可以吗? (与拥有易失性布尔值shouldStop相比)
  2. 这个解决方案正确吗?
  3. 我吞下InterruptedException正常吗?我不太感兴趣有人要求我的线程中断的代码段是什么。
  4. 有没有更短的方法来解决这个问题? (要点是具有“无限”循环)

编辑 在 catch 中为 InterruptedException 添加了对 interrupt() 的调用。

I'm trying to understand how threads work in Java and currently investigating how to implement looped threads that can be cancelled. Here's the code:

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");
}

The thread I create is indended to be interrupted sooner or later. So, I check isInterrupted() flag to decide whether I need to go on and also catch InterruptedException to handle cases when I'm in a kind of waiting operation (sleep, join, wait).

Things I'd like to clarify are:

  1. Is it fine to use interruption mechanism for this kind of task? (comparing to having volatile boolean shouldStop)
  2. Is this solution correct?
  3. Is it normal that I swallow InterruptedException? I'm not really interested what was the piece of code where someone asked my thread to interrupt.
  4. Are there any shorter ways to solve this problem? (the main point is having 'infinite' loop)

EDIT
Added call to interrupt() in catch for InterruptedException.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

稳稳的幸福 2024-12-06 08:01:10

我的回答是“不”。 3:

基本上问题是:中断异常有什么目的?它告诉你停止阻塞(例如睡觉)并早点返回。

有两种方法处理 InterruptedException:

  • 重新抛出它,使线程保持中断状态,
  • 再次设置 Thread.currentThread.interrupt() 并执行清理工作。这样你就可以确保线程中开始睡眠的另一个方法将再次抛出异常,

简单地吞下 InterruptedException 并不是一个好主意,因为这种中断的目的是最终终止。但您只会被要求打断,以便您还有时间进行清理。

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

编辑

否则我认为你所做的很好。不过,对我来说有点令人惊讶,因为我从未见过有人在自己的代码中真正这样做过。

可以在这里找到解释原因的有趣文章: http://www .ibm.com/developerworks/java/library/j-jtp05236/index.html

I am answering no. 3:

Basically the question is: What purpose does an Interrupted exception have? It tells you to stop blocking (e.g. sleeping) and return early.

There are two ways dealing with an InterruptedException:

  • Rethrow it, so the thread remains interrupted
  • set Thread.currentThread.interrupt() again and do your cleanup work. This way you can be sure that another method in your thread starting to sleep will throw again

Simply swallowing an InterruptedException is not a good idea regarding the purpose of such an interrupt which is to finally terminate. But you are only asked to interrupt so you still have time to clean up.

In this case this might be an 'overreaction' of myself, but typically such code is much more complicated and how do you know, that some follow-up-code in this Thread would not call a blocking method again?

EDIT

Otherwise I think what you're doing is fine. For me a bit surprising, though, because I never saw anyone in his own code actually doing it.

And interesting article explaining why can be found here: http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html

吖咩 2024-12-06 08:01:10
  1. 是的,没关系。您应该记录如何停止线程/可运行对象。您可以在 Runnable 实现上添加一个专用的停止方法来封装停止机制。使用中断,或使用专用布尔值,或两者兼而有之。
  2. 是的,除了好的做法是在捕获 InterruptedException 时恢复中断状态: Thread.currentThread().interrupt();
  3. 不,您应该恢复中断状态
  4. 据我所知没有
  1. Yes, it's fine. You should document how a Thread/Runnable must be stopped. You could add a dedicated stop method on your Runnable implementation that encapsulates the stopping mechanism. Either use interrupt, or use a dedicated boolean value, or both.
  2. Yes, except the good practice is to restore the interrupt status when catching InterruptedException: Thread.currentThread().interrupt();
  3. No, you should restore the interrupt status
  4. None that I'm aware of
嘴硬脾气大 2024-12-06 08:01:10

1)根据Java Concurrency in Practice一书,您的示例中的方式优于使用易失性标志(这是多余的,因为您已经有了中断标志)。这就是 InterruptedExceptions 的用途。

2)是的

3)只要恢复中断标志状态就可以吃掉异常。该异常并不代表错误,因此吃掉它不会丢失任何信息,它纯粹是一种转移控制的手段。 (恢复中断标志状态对于您有嵌套控制结构的情况非常重要,每个控制结构都需要被告知线程正在取消,对于像您这样的简单示例来说,这是很好的形式,但如果它丢失了,也不会造成任何损害。)

4 ) 不

1) The way in your example is preferable to using a volatile flag (which is redundant since you already have the interrupted flag), according to the Java Concurrency in Practice book. It is how InterruptedExceptions were intended to be used.

2) Yes

3) you can eat the exception as long as you restore the interrupt flag status. The exception doesn't represent an error so eating it doesn't lose any information, it is purely a means of transferring control. (Restoring the interrupt flag status is important for cases where you have nested control structures that each need to be informed that the thread is cancelling, for a simple example like yours it's good form but if it's missing it won't hurt anything.)

4) no

舟遥客 2024-12-06 08:01:10

使用中断很好,但要用好它们。您必须在 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();
    }
}

另一件事是,在等待 InputStreams 时,中断 并不总是起作用。然后,您可以使用(对于某些)InterruptedIOException,但它并不总是有效。要了解这些情况,您可能想尝试这段代码:

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();
    }
}

It's fine to use Interruption, but use them well. You have to re-throw Thread.currentThread().interrupt() in your catch. Here is a piece of code showing why :

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();
    }
}

Another thing is, Interruptions don't always work when waiting on InputStreams. You then can use (for some) InterruptedIOException, but it won't always work. To understand these cases, you might want to try this piece of code :

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();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文