您好,我有一个运行良好的 GUI 应用程序。我创建了一个套接字服务器。当我在程序中创建服务器类的新对象时,GUI 应用程序停止响应。
这是我的服务器类。如果我这样做
Server s = new Server();
在我的主应用程序中它停止工作。我应该如何添加它?开新线程?我试过了
Thread t = new Thread(new Server());
t.start();
但问题依然存在。拜托,我会感谢你的帮助。
package proj4;
import java.net.*;
import java.io.*;
public class Server implements Runnable {
ServerSocket serverSocket = null;
Socket clientSocket = null;
ObjectOutputStream out = null;
ObjectInputStream in = null;
int port;
static int defaultPort = 30000;
boolean isConnected = false;
Thread thread;
DataPacket packet = null;
public Server(int _port) {
try {
serverSocket = new ServerSocket(_port);
serverSocket.setSoTimeout(1000*120); //2 minutes time out
isConnected = true;
System.out.println("server started successfully");
thread = new Thread(this);
thread.setDaemon(true);
//thread.run();
} catch (IOException e) {
System.err.print("Could not listen on port: " + port);
System.exit(1);
}
try {
System.out.println("Waiting for Client");
clientSocket = serverSocket.accept();
System.out.println("Client Connected");
thread.run();
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
try {
out = new ObjectOutputStream(clientSocket.getOutputStream());
System.out.println("output stream created successfully");
} catch (IOException e) {
e.printStackTrace();
}
try {
in = new ObjectInputStream(clientSocket.getInputStream());
System.out.println("input stream created successfully");
} catch (IOException e) {
e.printStackTrace();
}
}
public Server() {
this(defaultPort); //server listens to port 30000 as default
}
public void run() {
System.out.println("Thread running, listening for clients");//debugging purposes
while (isConnected) {
try {
packet = this.getData();
Thread.sleep(0);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public DataPacket getData() {
try {
packet = (DataPacket)in.readObject();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return packet;
}
public void sendData(DataPacket dp) {
try {
out.writeObject(dp);
} catch (IOException e) {
e.printStackTrace();
}
try {
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public void closeConnection() throws IOException {
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
}
最佳答案
您的 Server
构造函数可能无限期地阻塞在 accept()
中。
关于 Swing 程序的两件事:
- 永远不要在 Swing 事件线程中执行任何长时间的任务,并且,
- 切勿在 Swing 事件线程之外操作任何 Swing 对象,除非所使用的方法被明确记录为线程安全的。
这意味着,如果服务器是从 Swing 事件线程启动的——也就是说,如果它是为了响应按钮单击等而启动的——那么是的,您必须为您的服务器对象生成另一个线程。否则,您保证 Swing 事件线程将被阻塞,直到您的线程退出。
您说即使您为服务器生成另一个线程,您的应用程序仍会停止响应?确保您调用的是 Thread.start()
而不是 run()
,否则您仍然会意外地在自己的线程中实际运行“新线程”而阻塞自己.
注意事项:
- 我看到您在 run() 循环中执行了
Thread.sleep(0);
。这不能保证做任何事情。如果你有一个单 CPU 机器,这可能会被公平地实现为一个空操作,允许同一个线程继续运行。 - 您真的希望
isConnected
是volatile
—— 否则无法保证除了更改它的线程之外的任何线程都会看到对此变量的更改. - 您无需在任何地方将
isConnected
设置为 false,因此您的run()
将一直运行,直到 JVM 停止或该线程出现 RuntimeException。< - It is discouraged在构造函数中启动线程。 (参见 Java Concurrency In Practice。)
- 在进入线程的
run()
方法之前,您不想在ServerSocket
上accept
!否则您的构造函数将阻塞等待连接并且不会将控制权返回给事件线程! - 您的构造函数中有以下代码:
您的代码是:
thread = new Thread(this);
thread.setDaemon(true);
//thread.run();
当您没有注释掉 thread.run()
时,您没有开始一个新线程!为此,您需要执行 thread.start()
。相反,您在调用构造函数的同一个线程中运行这个新线程(由于上面的原因 #3,它永远不会停止)。您现在编写代码的方式会记录所有 IOExceptions,但会被吞没。您可能希望在任何 IOException
以及 closeConnection()
中将 isConnected
设置为 false
。
关于java - 多线程和Java Swing问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/720244/