简体   繁体   English

Java Swing GUI 冻结

[英]Java swing GUI freezes

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.所以在 ss.accept() 返回一个值之后,它会在单独的线程中创建新的套接字实例。

After clicking the button the GUI freezes because inside the socket.listen method there is an infinite loop.单击按钮后,GUI 会冻结,因为在 socket.listen 方法中存在无限循环。 How can I avoid that?我怎样才能避免这种情况?

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 ss.accept()是一个阻塞调用,因此您的 UI 将冻结,直到有传入连接
  2. Never run while(true) loops in the EDT.永远不要在 EDT 中运行while(true)循环。

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.每当您有传入连接时,创建另一个线程来获取传入客户端连接并处理它。

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.这会将 EDT(事件调度线程)置于无限循环中,并且您的 GUI 变得无响应。 So, delete this line.所以,删除这一行。

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 运行它

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. 1) 如果您正在编写 GUI 应用程序,则可能在 Swing 中永远不要在事件调度程序线程或事件处理程序中调用阻塞方法。 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().例如,如果您在单击按钮时正在读取文件或打开网络连接,请不要在 actionPerformed() 方法上执行此操作,而只需创建另一个工作线程来完成该工作并从 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.这将使您的 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

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.您的代码基本上冻结了 GUI,因为所有事件都在事件调度程序线程 (EDT) 上执行,该线程负责处理您的所有 GUI 内容和相应的事件。 If you either block it, stop it or throw in loops it will affect on its performance.如果您阻止它,停止它或投入循环,它将影响其性能。

Try these...试试这些...

1. During getting the initial connection delay can occur, so first create and empty socket,then try to connect to the server. 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..

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

    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM