确保线程被中断

时间:2018-02-16 15:05:59

标签: java multithreading concurrency

我想中断一个线程,该线程在无限循环的每个增量中检查被中断的标志。退出循环的唯一方法是抛出InterruptedException。

在可中断线程执行的(不可访问的)代码中的某个地方,一个睡眠操作正在声明一个InterruptedException和一个吞噬异常的catch块。在一个不幸的情况下,线程将在执行sleep方法时被中断,导致中断的标志被重置。在这种情况下,线程不会退出无限循环。

避免这种情况的最佳策略是什么?我在下面的代码中的主线程在循环中调用中断,直到可中断的线程不再存在为止。这是一个合理的策略吗?有哪些替代方案?

 public class InterruptableThreads extends Thread {

    public static Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                while (true) {

                    if (Thread.currentThread().isInterrupted()) {
                        throw new InterruptedException();
                    }

                    try {
                        Thread.sleep(5000);
                    } catch (Exception e) {
                        System.out.println("Swallowing exception. Resetting interrupted flag");
                    }

                    System.out.println("t1 run");
                }
            } catch (InterruptedException e) {
                System.err.println("t1 interrupted.");
            }
        }

    });

    public static void main(String[] args) throws InterruptedException {

        t1.start();

        Thread.sleep(4000);

        while (t1.isAlive()) {
            t1.interrupt();
        }

        t1.join(1000);

        System.out.println("Finished!");


    }
}

2 个答案:

答案 0 :(得分:1)

你提出的解决方案,包括循环直到线程死亡应该工作。我不知道这是否可行,但您可能希望通过在该循环中包含join语句来避免主动旋转:

    while (t1.isAlive()) {
        t1.interrupt();
        try {
            t1.join(1000);

        } catch(InterruptedException e) {
            ...
        }
    }

另一种方法是将中断吞咽代码的执行与可中断线程的主循环隔离开来:

public static Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<?> f = null;

        try {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    throw new InterruptedException();
                }

                f = executor.submit(new Runnable() {
                    // swallowing code
                });

                try {
                   f.get();

                } catch(CancellationException e) {
                  ...
                } catch(ExecutionException e) {
                  ...
                } // interrupted exceptions will be thrown from get() but not caught here                 

                System.out.println("t1 run");
            }
        } catch (InterruptedException e) {
            System.err.println("t1 interrupted.");
            if (f != null) {
              f.cancel(true);
            }

        } finally {
            executor.shutdownNow();
        }
    }

});

f.get()将为您提供捕获t1中断的可能性,无论执行程序服务在哪里执行外部代码并且可能&#34;睡眠&#34旋转的线程状态如何;

但是添加另一个线程会带来额外的复杂性以及与之相关的风险。

答案 1 :(得分:0)

Brian Goetz在 Java Concurrency in Practice 中概述了最佳策略。从内存中,您可以从catch块中重新中断线程,或者抛出异常。

此外,尽可能抓住最窄的异常,而不是<TextBox x:Name="Filter" TextChanged="Filter_TextChanged" />

Exception