如何在退出前安全关闭所有线程

我有一个启动几个线程的应用程序,最终一个线程可能需要退出整个应用程序,但是其他线程可能处于任务中间,所以我想让它们在退出之前继续当前循环。


在下面的示例中,线程 2 不知道线程 1 何时尝试退出,它只是强制一切立即完成。


我怎样才能让 Thread2、3 和 4 等在关闭之前完成它们的循环?


编辑:为了解决重复的问题:这与父类不能负责操纵关闭的典型情况不同,任何单个线程都必须能够启动关闭。


Edit2:我还留下了我最终做的答案,这是已接受答案的实现。


class Scratch {

    public static void main(String[] args) {

        Thread Task1 = new Thread(new Task1());

        Task1.start();


        Thread Task2 = new Thread(new Task2());

        Task2.start();


        // ... more threads

    }


    public class Task1 implements Runnable {

        public void run() {

            while (true) {

                // ...

                System.exit(0);

                // ...

            }

        }

    }


    public class Task2 implements Runnable {

        public void run() {

            while (true) {

                // ...

                // I need to know about System.exit(0) to exit my loop

                // ...

            }

        }

    }

}


拉风的咖菲猫
浏览 509回答 3
3回答

智慧大石

您可以使用volatile boolean所有线程将不断检查的变量。如果一个线程将该变量的值设置为false,则所有线程都将看到新值并离开while循环。说明:volatile变量中的读/写操作是原子的。除此之外,volatile 变量的值不会被缓存,所以所有线程看到的都是相同的值。class Scratch {    private static volatile boolean isRunning = true;    public static void main(String[] args) {        Thread Task1 = new Thread(new Task1());        Task1.start();        Thread Task2 = new Thread(new Task2());        Task2.start();        // ... more threads    }    public class Task1 implements Runnable {        public void run() {            while (isRunning) {                // ...                isRunning = false; // let's stop all threads                // ...            }        }    }    public class Task2 implements Runnable {        public void run() {            while (isRunning) {                // ...                // I need to know about System.exit(0) to exit my loop                // ...            }        }    }}

侃侃无极

自己创建线程被认为是“不好的做法”,您应该考虑使用 ExecutorService。同步应该通过中断线程来完成。class Scratch {&nbsp; &nbsp; private final ExecutorService executorService;&nbsp; &nbsp; public Scratch(ExecutorService es) {&nbsp; &nbsp; &nbsp; &nbsp;this.executorService = es;&nbsp; &nbsp; }&nbsp; &nbsp; /** Convience constructor */&nbsp; &nbsp; public Scratch() {this(Executors.newCachedThreadPool());}&nbsp; &nbsp; public class Task1 implements Callable<Void> {&nbsp; &nbsp; &nbsp; &nbsp; public Void call() throws Exception {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(true) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; executorService.shutdownNow(); // interrupt all running threads&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// (including Task1) started by&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// given executor service&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (Thread.interrupted())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new InterruptedException();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return null;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp;public class Task2 implements Callable<Void> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public Void call() throws Exception {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;while(true) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// check if the thread was interrupted, if so throw Exception&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (Thread.interrupted())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new InterruptedException();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return null;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp;public static void main(String ... args) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Scratch s = new Scratch();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s.executorService.submit(new Task1());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;s.executorService.submit(new Task2());&nbsp; &nbsp; &nbsp;}&nbsp;}

鸿蒙传说

除了使用volatile boolean variable实现的方法(这是一个很好的方法)之外,您还可以考虑使用listeners。它们通常在 Android API 中使用。首先,创建定义侦听器的接口。下面是一个例子:public interface TaskListener {&nbsp; &nbsp; public void onFinish();}现在,在您希望收到任务完成通知的类上实现此接口。往下看:public class Task2 implements Runnable, TaskListener {&nbsp;&nbsp; &nbsp; public void run() {&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; while (!Thread.currentThread().isInterrupted()) {&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //...&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; }&nbsp; &nbsp; public void onFinish() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//perform your exit operations here.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Thread.currentThread().interrupt();&nbsp; &nbsp; }&nbsp;}现在,准备您的主要任务的类以接收侦听器。看一看:public class Task1 implements Runnable {&nbsp;&nbsp; &nbsp; private ArrayList<TaskListener> listeners = new ArrayList<>();&nbsp; &nbsp; public void run() {&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; while (true) {&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // ...&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.finish();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // ...&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; public void addListener (TaskListener listener) {&nbsp; &nbsp; &nbsp; &nbsp; this.listeners.add(listener);&nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; private void finish() {&nbsp; &nbsp; &nbsp; &nbsp; for(TaskListener listener: this.listeners) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;listener.onFinish();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; }&nbsp;&nbsp;}完成所有设置后,现在可以轻松聆听任务的完成情况。往下看:public static void main(String[] args) {&nbsp;&nbsp; &nbsp; Thread task1 = new Thread(new Task1());&nbsp;&nbsp; &nbsp; Thread task2 = new Thread(new Task2());&nbsp;&nbsp; &nbsp; task1.addListener(task2);&nbsp; &nbsp; task1.start();&nbsp; &nbsp; task2.start();}&nbsp;完毕!现在,每次task1.finish()调用时,它的所有侦听器(仅task2在此示例中)都会收到通知(onFinish调用它们的方法)。注意:TaskListener如果您不想,则没有必要在您的所有任务中实施。这是一个使用lambda 表达式的示例:public static void main(String[] args) {&nbsp;&nbsp; &nbsp; Thread task1 = new Thread(new Task1());&nbsp;&nbsp; &nbsp; Thread task2 = new Thread(new Task2());&nbsp;&nbsp; &nbsp; task1.addListener(() -> {&nbsp; &nbsp; &nbsp; &nbsp; //this entire block will be called when task1 finishes&nbsp; &nbsp; &nbsp; &nbsp; task2.interrupt();&nbsp; &nbsp; });&nbsp; &nbsp; task1.start();&nbsp; &nbsp; task2.start();}&nbsp;注2:我在手机上写了这个答案。虽然我修改了几次代码,看起来还可以,但我要回家才能测试它
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java