我的问题是,我无法找到一种方法,有一个线程“点击一个按钮启动,并停止点击另一个按钮”,然后如果我点击相同的开始按钮一个新的线程启动,确实与第一次操作相同。所以基本上只是一个新的实例。
在我的程序中,我有一个服务器应用程序,有2个按钮和2个文本字段。在用户输入正确的用户名和密码后,Server应用程序将打开一个新的ServerSocket,用于侦听要连接的客户端。这是在一个单独的线程中完成的,以防止GUI冻结。按下停止按钮后,线程停止。
当我在GUI中再次按下启动按钮时,如何让我的程序启动一个新的Thread,与第一个一样?我是否必须使用循环?
服务器应用代码:
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() {
}
}
我的Runnable代码:
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) {
}
}
}
概观
虽然thread
的创建在Java中是有效的,但由于种种原因,它非常气馁。最重要的一点是,thread
的创建是相当昂贵和资源密集的。此外,标准库中实现了更安全/有效的模型,可用于简化问题。在这种特殊情况下,由于操作的性质,我会建议不要使用此实现;开始 - 停止重复发生。注意,thread
一旦启动就无法重启,并且在执行时停止线程的唯一方法是调用interrupt()
。不幸的是,中断线程需要开发人员在run()
方法中实现错误处理。下面我们将看到run()
或Runnable
实现的Thread
方法。
public void run() {
try {
// Your connection logic would be here
yourLogic();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // Maintain status
}
}
让我们假设您制作了自己的thread
实现,称为MyThreadImpl
。下面我们将看到如何利用它:
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类,因为它具有强大的实现和理想的控制。 CompletableFutures利用全局ForkJoinPool.common()
进行线程化,以便应用程序可以更高效地执行。此外,您可以接收对象内的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
}
...
}
Java一旦完成执行就不允许重新启动线程。
中断您创建的线程将完成其执行。这里的问题是你使用完成执行的相同线程(一旦点击停止按钮)。
我建议以下之一:
我希望这有帮助。