Java swing的GUI冻结

我正在编写一个使用套接字的Java客户端/服务器GUI应用程序,这里是问题:

我有一个button来开始监听指定的端口:

buttonactionPerformed方法

private void listenButtonActionPerformed(java.awt.event.ActionEvent evt) { int port = Integer.parseInt(portTextfield.getText(), 10); try { socket.listen(port); } catch (IOException ex) { } } 

这里是socket.listen方法

 public static void listen() throws IOException { ServerSocket ss = new ServerSocket(port); while (true) new socket(ss.accept()); } 

“套接字”类扩展“线程”
所以在ss.accept()返回一个值之后,它会在单独的线程中创build新的套接字实例。

点击button后,GUI会冻结,因为在socket.listen方法中存在无限循环。 我怎样才能避免呢?

你的devise有两个缺陷:

  1. ss.accept()是一个阻塞调用,所以你的UI将冻结,直到有一个传入的连接
  2. 永远不要在EDT while(true)环中运行。

而是执行以下操作:

  • 点击button时,创build一个将开始监听传入连接的线程。
  • 每当你有一个传入的连接,创build另一个线程,将采取传入的客户端连接并处理它。

只要你的

 new socket(ss.accept()); 

立即返回,你只需要改变你的

 while (true) 

这使EDT(Event Dispatch Thread)陷入无限循环,并且GUI变得无法响应。 所以,删除这一行。

如果你不能使用SwingWorker类( http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html#process(java.util.List )创build一个嵌套类在你的listenButtonActionPerformed(java.awt.event.ActionEvent evt)方法中调用一个swingWoker.execute(); (创build它的对象之后)。

请参阅教程: http : //docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

永远不要创build一个新的线程,并从Swing EDT运行它

您将需要使用multithreading。 如果我在哪里,我将把GUI代码和服务器代码分开,当按下button时,我只需将Server代码作为新的Thread启动。

你的代码基本上冻结了GUI,因为所有的事件都是在事件调度线程(EDT)上执行的,这个线程负责处理你所有的GUI事件和事件。 如果你阻止它,阻止它或者循环,这将影响它的性能。

看看这个: http : //javarevisited.blogspot.ro/2012/02/what-is-blocking-methods-in-java-and.html

1)如果你正在编写GUI应用程序,可能是Swing从来没有在Event dispatcher线程或事件处理程序中调用阻塞方法。 例如,如果您正在读取文件或打开networking连接,单击button时不要在actionPerformed()方法上执行该操作,而只需创build另一个工作线程来完成该任务并从actionPerformed()返回。 这将保持您的GUI响应,但它又取决于devise,如果操作是需要用户等待的事情比考虑使用invokeAndWait()进行同步更新。

使用多个线程: http : //javarevisited.blogspot.ro/2011/02/how-to-implement-thread-in-java.html

试试这些…

1. During getting the initial connection delay can occur, so first create and empty socket,then try to connect to the server.

  `Socket s = new Socket();` `s.connect(new InetSocketAddress("ip_addr",port_nos),1000);` 

2. And Secondly always keep the Non-UI work out of Your UI thread..

这是我的服务器 – 客户端通信示例

客户端代码:

 public class ClientWala { public static void main(String[] args) throws Exception{ Boolean b = true; Socket s = new Socket(); s.connect(new InetSocketAddress("127.0.0.1", 4444),1000); System.out.println("connected: "+s.isConnected()); OutputStream output = s.getOutputStream(); PrintWriter pw = new PrintWriter(output,true); // to write data to server while(b){ if (!b){ System.exit(0); } else { pw.write(new Scanner(System.in).nextLine()); } } // to read data from server InputStream input = s.getInputStream(); InputStreamReader isr = new InputStreamReader(input); BufferedReader br = new BufferedReader(isr); String data = null; while ((data = br.readLine())!=null){ // Print it using sysout, or do whatever you want with the incoming data from server } } } 

服务器端代码:

 import java.io.* import java.net.*; public class ServerTest { ServerSocket s; public void go() { try { s = new ServerSocket(44457); while (true) { Socket incoming = s.accept(); Thread t = new Thread(new MyCon(incoming)); t.start(); } } catch (IOException e) { e.printStackTrace(); } } class MyCon implements Runnable { Socket incoming; public MyCon(Socket incoming) { this.incoming = incoming; } @Override public void run() { try { PrintWriter pw = new PrintWriter(incoming.getOutputStream(), true); InputStreamReader isr = new InputStreamReader( incoming.getInputStream()); BufferedReader br = new BufferedReader(isr); String inp = null; boolean isDone = true; System.out.println("TYPE : BYE"); System.out.println(); while (isDone && ((inp = br.readLine()) != null)) { System.out.println(inp); if (inp.trim().equals("BYE")) { System.out .println("THANKS FOR CONNECTING...Bye for now"); isDone = false; s.close(); } } } catch (IOException e) { // TODO Auto-generated catch block try { s.close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } e.printStackTrace(); } } } public static void main(String[] args) { new ServerTest().go(); } }