【问题标题】:How to restart the threads using ExecutorService which were terminated previously in a Swing application如何使用 ExecutorService 重新启动之前在 Swing 应用程序中终止的线程
【发布时间】:2019-05-07 08:11:42
【问题描述】:

我正在创建一个 Swing 应用程序。它包含一个 JFrame,在 JFrame 内部,我添加了一个 JButton 来启动和停止一些任务。我正在使用相同的 JButton 来启动和停止线程任务并由 ExecutorService 执行。

点击开始按钮时,线程将被执行,按钮标签将更改为停止,而点击停止按钮将停止所有线程(我已使用 ExecutorService shutdownNow() 方法完成此操作)和按钮标签将再次更改为开始,但不会关闭应用程序。 现在,如果我再次单击“开始”按钮,应用程序将被挂起,线程不会从头开始。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class MultipleThreads {
    public static ExecutorService executor = Executors.newFixedThreadPool(4);

    public static void main(String[] args) {
        JFrame frame = new JFrame("Stop Thread");
        frame.setSize(200,200);
        frame.setLocationRelativeTo(null);
        frame.setLayout(null);
        JPanel panel = new JPanel();
        panel.setBounds(5,5,150,150);
        panel.setLayout(null);
        JButton btn = new JButton("Start");
        btn.setBounds(10,10,80,25);

        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                if (btn.getText().equals("Start")) {
                    btn.setText("Stop");
                    MultipleThreads2 runThreads = new MultipleThreads2();
                    runThreads.runThreadMethod();
                } else if (btn.getText().equals("Stop")) {
                    try {
                        if (!executor.awaitTermination(800, TimeUnit.MILLISECONDS)) {
                            executor.shutdownNow();
                        } 
                    } catch (InterruptedException e) {
                        executor.shutdownNow();
                    }

                    btn.setText("Start");
                }
            }
        });
        panel.add(btn);
        frame.add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

class MultipleThreads2 {
    public volatile boolean flag = true;

    public void stopRunning() {
        flag = false;
    }

    public MultipleThreads2() {
        while (flag) {
            try {
                MultipleThreads.executor.submit(t1);
                MultipleThreads.executor.submit(t2);
                flag = false;
                System.out.println(t1.isAlive());
            } catch (Exception e) {

            }
        }
    }

    public void runThreadMethod() {
        flag = true;
        while (flag) {
            try {
                MultipleThreads.executor.submit(t3);
                MultipleThreads.executor.submit(t4);
                    flag = false;
            } catch (Exception e) {

            }
        }
    }

    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println("From t1 Thread");
                    Thread.sleep(1000);
                }
            } catch (Exception e) {

            }
        }
    });

    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println("From t2 Thread");
                    Thread.sleep(500);
                }
            } catch (Exception e) {

            }
        }
    });

    Thread t3 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println("From t3 Thread");
                    Thread.sleep(500);
                }
            } catch (Exception e) {

            }
        }
    });

    Thread t4 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println("From t4 Thread");
                    Thread.sleep(500);
                }
            } catch (Exception e) {

            }
        }
    });
}

预期:第二次单击“开始”按钮时应该从头开始重新启动所有线程。

【问题讨论】:

  • 无关:从不使用空的 catch 块。至少打印异常。你真的很想知道你的代码什么时候因为某种原因抛出。您正在学习事物是如何运作的,因此愿意研究令人惊讶的例外情况。甚至在以后,当您真正知道自己在做什么时,忽略异常确实是一种不好的做法。

标签: java multithreading swing executorservice


【解决方案1】:

这里:

public static ExecutorService executor = Executors.newFixedThreadPool(4);

您正在创建一次该线程池。稍后,您正在调用

executor.shutdownNow();

换句话说:你正在启动你的车,在某个时刻,你停下车,下车,然后把它点燃。然后你问自己:“好吧,我怎么用那辆车开车回家?”。好吧,你不能。你只是把它点燃了。

同样的事情:当你关闭服务时,它消失了

长话短说,简单(不一定是理想的)解决方案是:

public static ExecutorService executor = null;

及以后:

if (executor == null) 
  executor = Executors.newFixedThreadPool(4);

executor.shutdownNow();
executor = null;

换句话说:你开着你的车开着车着火,然后你买了一辆新的,在着火之前再开一辆。

当然,设置为 null 并对其进行检查的方法可能会导致各种问题。这样做会更好一些:

  executor.shutdownNow();
  executor = Executors.newFixedThreadPool(4);

含义:只要“最后一个”被告知关闭,您只需创建一个新实例,而不是将执行程序保留为空。因此,理论上,每当执行器习惯于提交任务或它被关闭时,您都在与当前“有效”的实例交谈。

【讨论】:

  • 清晰而精彩的解释。
  • 另外,我还有一个问题,在上面的代码中,我想先执行线程 t1 和 t2,一旦这两个线程完成,然后 t3 和 t4 线程应该开始执行。我怎样才能做到这一点?你能帮帮我吗?
  • @AbiSaran 请记住,stackoverflow 就像“一个问题,一个/多个答案”。因此,与 cmets 一起提出不同的问题并不是这里真正的工作方式。您可以考虑为此提出一个新问题。不过话虽如此......
  • 例如,您可以查看stackoverflow.com/questions/7939257/…。这真的取决于:您是否希望线程完成(然后您可以/应该使用诸如 wait()/notify() 之类的东西),还是更多关于“任务”的完成?长话短说:这些都是非常基本的模式,你可以在那里找到大量的好资源。所以我的建议:先做一些(网络)研究,当你仍然不确定,或者你写的代码不起作用时,在这里写一个新问题。
  • 也许,我们应该谈谈创建Thread 实例并将它们提交到ExecutorService 的根本错误,而不仅仅是提交Runnables。此外,当没有先前的关闭调用时,调用awaitTermination 是没有意义的。通常,正确的做法是保留 submit 返回的 Futures 并取消它们,然后,无需通过关闭线程池并创建新线程池来破坏线程池的实际目的。跨度>
猜你喜欢
  • 1970-01-01
  • 2020-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多