Java Swing GUI 冻结

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11185485/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 04:07:35  来源:igfitidea点击:

Java swing GUI freezes

javaswingsocketsuser-interfaceconcurrency

提问by Nick Sanders

I am writing a Java client/server GUI application using sockets and here is the problem:

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

I have a button to start listening for a specified port:

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

button actionPerformed method

按钮 actionPerformed 方法

private void listenButtonActionPerformed(java.awt.event.ActionEvent evt) {                                             
    int port = Integer.parseInt(portTextfield.getText(), 10);

    try {
        socket.listen(port);
    } catch (IOException ex) {
    }
}

Here is the socket.listen method

这是 socket.listen 方法

public static void listen() throws IOException {
    ServerSocket ss = new ServerSocket(port);

    while (true)
        new socket(ss.accept());
}

"socket" class extends "Thread"
So after ss.accept() returns a value it creates new socket instance in separate thread.

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

After clicking the button the GUI freezes because inside the socket.listen method there is an infinite loop. How can I avoid that?

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

采纳答案by GETah

You have two pitfalls in your design:

你的设计有两个陷阱:

  1. ss.accept()is a blocking call so your UI will freeze until there is an incoming connection
  2. Never run while(true)loops in the EDT.
  1. ss.accept()是一个阻塞调用,因此您的 UI 将冻结,直到有传入连接
  2. 永远不要while(true)在 EDT 中运行循环。

Instead do the following:

而是执行以下操作:

  • When the button is clicked create a thread that will start listening for incoming connections.
  • Whenever you have an incoming connection, create another thread that will take the incoming client connection and deal with it.
  • 单击按钮时,创建一个线程,该线程将开始侦听传入连接。
  • 每当您有传入连接时,创建另一个线程来获取传入的客户端连接并处理它。

回答by vedant

as long as your

只要你的

new socket(ss.accept());

returns immediately, you only need to change your

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

while (true)

this puts the EDT (Event Dispatch Thread) into an infinite loop and your GUI becomes irresponsive. So, delete this line.

这会将 EDT(事件调度线程)置于无限循环中,并且您的 GUI 变得无响应。所以,删除这一行。

If you can't then use the SwingWorker class ( http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html#process(java.util.List) Create a nested class that extents SwingWorker. Just call a swingWoker.execute();(after you have created its object) in your listenButtonActionPerformed(java.awt.event.ActionEvent evt)method.

如果您不能使用 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();(在您创建其对象之后)。

See the tutorial: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

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

Never create a new thread and run it from from the Swing EDT

永远不要创建新线程并从 Swing EDT 运行它

回答by npinti

You will need to use Multi-Threading. If I where you, I would separate the GUI code and the server code and when the button is pressed, I simply launch the Server code as a new Thread.

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

Your code is freezing the GUI basically because all events are executed on the Event Dispatcher Thread (EDT) which is the thread which takes care of all your GUI stuff and respective events. If you either block it, stop it or throw in loops it will affect on its performance.

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

回答by CosminO

Check this out: http://javarevisited.blogspot.ro/2012/02/what-is-blocking-methods-in-java-and.html

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

1) If you are writing GUI application may be in Swing never call blocking method in Event dispatcher thread or in the event handler. for example if you are reading a file or opening a network connection when a button is clicked don't do that on actionPerformed() method, instead just create another worker thread to do that job and return from actionPerformed(). this will keep your GUI responsive, but again it depends upon design if the operation is something which requires user to wait than consider using invokeAndWait() for synchronous update.

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

Using multiple threads: http://javarevisited.blogspot.ro/2011/02/how-to-implement-thread-in-java.html

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

回答by Kumar Vivek Mitra

Try these...

试试这些...

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

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..

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

Here is my Example of Server - Client Communication..

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

Client side code:

客户端代码:

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

    }




    }
}

Server side code:

服务器端代码:

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

    }

}