停止当前线程然后创建一个执行相同操作的新线程?

Stop current Thread and then create a new thread that performs the same operation?

我的问题是我想不出一种方法来拥有一个 "on the click of a button starts, and stops on the click of another button" 的线程,然后如果我单击同一个启动按钮,一个新线程将启动,它执行与第一个线程完全相同的操作。所以基本上只是一个新实例。

在我的程序中,我有一个具有 2 个按钮和 2 个文本字段的服务器应用程序。用户输入正确的用户名和密码后,服务器应用程序会打开一个新的 ServerSocket,用于侦听要连接的客户端。这是在单独的线程中完成的,以防止 GUI 冻结。按下停止按钮后,线程停止。

当我在 GUI 中再次按下启动按钮时,如何让我的程序启动一个与第一个线程相同的新线程?我是否必须使用循环?

服务器应用代码:

public class Server extends JFrame implements ActionListener {

    JLabel instructionsLabel;
    JLabel passwordLabel;
    JPasswordField passwordTF;
    JButton shutdownButton;
    JButton startupButton;
    JLabel usernameLabel;
    JTextField usernameTF;
    Thread MyThread = new Thread(new ServerRunnable());

    public Server() {
        super("Server");
        initComponents();
    }
                               // My problem is here
    public void starterMeth() {
        MyThread.start();
    }

    public void stopMeth() {
        MyThread.interrupt();
    }
                                // in these 2 methods
    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();

        String f = "n";
        ConnectionBean cb = new ConnectionBean();

        char[] a = passwordTF.getPassword();
        String b = new String(a);
        String inputDetails = usernameTF.getText() + b;

        Iterator it = cb.getDetails().iterator();
        while (it.hasNext()) {
            Object next = it.next();
            if (inputDetails.equals(next)) {
                f = "y";
                if (source == startupButton) {
                    if (!MyThread.isInterrupted()) {
                        starterMeth();
                        JOptionPane.showMessageDialog(null,
                            "Congratulations! Server started.",
                            "Start-up Message",
                            JOptionPane.INFORMATION_MESSAGE);
                    } else {
                        JOptionPane.showMessageDialog(null,
                            "Please restart the server application.",
                            "Start-up Message",
                            JOptionPane.INFORMATION_MESSAGE);
                    }
                } else if (source == shutdownButton) {
                    stopMeth();
                    JOptionPane.showMessageDialog(null,
                        "Server shut-down successfully!",
                        "Shut-down Message",
                        JOptionPane.INFORMATION_MESSAGE);
                }
                // only resets the text fields when the correct details are entered
                passwordTF.setText("");
                usernameTF.setText("");
            }
        }
        if (f.equals("n")) {
            JOptionPane.showMessageDialog(null, "Invalid username or password.", "Alert", JOptionPane.WARNING_MESSAGE);
        }
        cb.setCloseConnection(true);
    }

    private void initComponents() {
    }
}

我的可运行代码:

public class ServerRunnable implements Runnable {

    @Override
    public void run() {

        try {
            ServerSocket ss = new ServerSocket(7777);

            while(true) {
                Socket cs = ss.accept();
                new ClientThread(cs).start();
        }
        } catch (IOException ex) {
        }
    }
}

Java 不允许在线程具有后重新启动线程完成执行.

中断您创建的线程只会结束它的执行。这里的问题是您正在使用已完成执行的同一个线程(单击停止按钮后)。

我建议以下其中一项:

  1. 改进您的可运行程序,以便当用户尝试单击 shutdownButton 按钮时,它会停止正在执行的操作,并获取一些某种信号量使其成为 "sleep" 直到再次点击 startupButton
  2. (更简单)始终在 starterMeth 上创建一个新线程。不要忘记检查线程是否 运行 并在启动新线程之前中断它。

希望对您有所帮助。

概览

尽管 thread 的创建在 Java 中有效,但出于多种原因,强烈建议不要这样做。最重要的是 thread 的创建非常昂贵且需要大量资源。此外,标准库中实现了很多 safer/efficient 模型,可用于简化问题。在这种特殊情况下,由于操作的性质,我建议不要使用这种实现方式; 启停反复出现。请注意,thread 一旦 启动 就无法重新启动,并且在执行时停止线程的唯一方法是调用 interrupt()。不幸的是,中断线程需要开发人员在 run() 方法中实现错误处理。下面我们将看到 RunnableThread 实现的 run() 方法。

public void run() {
    try {
        // Your connection logic would be here
        yourLogic();
    } catch (InterruptedException ie) {
        Thread.currentThread().interrupt(); // Maintain status
    }
}

假设您自己制作了名为 MyThreadImplthread 实现。下面我们将看到如何使用它:

public void starterMeth() {
    Thread myThread = new MyThreadImpl(); // Create thread
    myThread.start(); // Start execution in parallel
}

public void stopMeth() {
    myThread.interrupt(); // Stop the thread
}

或者,如果您像在此应用程序中一样实现自己的 Runnable,它会如下所示:

public void starterMeth() {
    Thread myThread = new Thread(new ServerRunnable()); // Create thread
    myThread.start(); // Start execution in parallel
}

public void stopMeth() {
    myThread.interrupt(); // Stop the thread
}

虽然这两个都是有效的,但还有更好的方法。

更好的方法

我的建议是利用对象中的 CompletableFuture class due to its robust implementation and desirable control. CompletableFutures utilize the global ForkJoinPool.common() for its threading so that the application can execute with more efficiency. In addition, you can receive the Future 供以后使用,而不是每次都尝试重新创建它。让我们在下面研究一下这个实现是如何工作的:

public class Server {
    CompletableFuture<Void> myFuture;
    ...

    public void starterMeth() {
        myFuture = new CompletableFuture<Void>(); // Create future
        myFuture.runAsync(new ServerRunnable()); // Start execution in parallel
    }

    public void stopMeth() {
        myFuture.cancel(true); // Stop the future
    }

    ...
}