【问题标题】:Java swing GUI freezesJava swing GUI 冻结
【发布时间】:2012-06-26 11:33:01
【问题描述】:

我正在使用套接字编写 Java 客户端/服务器 GUI 应用程序,问题出在:

我有一个按钮可以开始监听指定端口:

按钮动作执行方法

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());
}

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

单击按钮后,GUI 冻结,因为在 socket.listen 方法中存在无限循环。我怎样才能避免这种情况?

【问题讨论】:

  • 请问您有什么问题...,尽快发布 SSCCE 以获得更好的帮助
  • 作为参考,有一个工作示例here

标签: java swing sockets user-interface concurrency


【解决方案1】:

您的设计中有两个陷阱:

  1. ss.accept() 是一个阻塞调用,因此您的 UI 将冻结,直到有传入连接
  2. 切勿在 EDT 中运行 while(true) 循环。

改为执行以下操作:

  • 单击该按钮后,创建一个线程,该线程将开始侦听传入连接。
  • 只要有传入连接,请创建另一个线程来处理传入的客户端连接。

【讨论】:

    【解决方案2】:

    只要你的

    new socket(ss.accept());
    

    立即返回,您只需要更改您的

    while (true)
    

    这会使 EDT(事件调度线程)进入无限循环,您的 GUI 变得无响应。所以,删除这一行。

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

    见教程:http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

    切勿创建新线程并从 Swing EDT 运行它

    【讨论】:

      【解决方案3】:

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

      1) 如果您正在编写 GUI 应用程序,可能在 Swing 中永远不会调用 事件调度程序线程或事件处理程序中的阻塞方法。 例如,如果您正在读取文件或打开网络连接 单击按钮时不要在 actionPerformed() 方法上执行此操作, 相反,只需创建另一个工作线程来完成该工作并返回 来自 actionPerformed()。这将使您的 GUI 保持响应,但再次 如果操作是需要的,这取决于设计 用户等待而不是考虑使用 invokeAndWait() 进行同步 更新。

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

      【讨论】:

        【解决方案4】:

        您将需要使用多线程。如果我在哪里,我会将 GUI 代码和服务器代码分开,当按下按钮时,我只需将服务器代码作为新线程启动。

        您的代码基本上冻结了 GUI,因为所有事件都在事件调度线程 (EDT) 上执行,该线程负责处理所有 GUI 内容和相应事件。如果你阻止它,停止它或抛出循环,它会影响它的性能。

        【讨论】:

          【解决方案5】:

          试试这些...

          1. During getting the initial connection delay can occur, so first create and emptysocket,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();
          
              }
          
          }
          

          【讨论】:

            猜你喜欢
            • 2012-09-25
            • 2013-11-05
            • 1970-01-01
            • 1970-01-01
            • 2021-11-09
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多