使用用户界面 (Swing) 在 Java 上启动 ServerSocket 冻结

Starting ServerSocket on Java with User Interface(Swing) Freezes

美好的一天,

我有一个 ServerSocket 的无限循环,工作正常...问题是当我尝试使用按钮启动 ServerSocket 时。我的用户界面 "Freeze" 没有任何变化,但服务器正常运行,这里我有一个 ScreenShot:

http://i.gyazo.com/15d331166dd3f651fc7bda4e3670be4d.png

当我按下按钮时 "Iniciar" 表示启动服务器,用户界面冻结(ServerSocket 无限循环)。 我无法更改我的代码,因为它工作正常。

    public static void iniciarServer() {

    try {
        appendString("\nServidor iniciado.");
        System.out.println("asdasd");
    } catch (BadLocationException e1) {
        e1.printStackTrace();
    }

    try {
        ss = new ServerSocket(1234, 3);
        while (true) {
            System.out.println("Esperando conexiones...");
            appendString("\nEsperando conexiones...");
            Socket s = ss.accept();
            System.out.println("Conexión entrante: " + s.getRemoteSocketAddress());
            appendString("\nConexión entrante: " + s.getRemoteSocketAddress());

            conexiones++;
            //System.out.println("Debug: conexiones SERVER: " + conexiones);
            MultiThread mt = new MultiThread(s, conexiones);
            mt.start();
            ///////////////////////////////////////////////////////////////
        }
    } catch (IOException e) {
        System.out.println("Error Server: " + e.getMessage());
    } catch (BadLocationException e) {
        e.printStackTrace();
    } 
    stopServer();
}

appendString(); 用于向 JTextPane 添加一些文本,但不起作用,因为 UI 冻结。

有什么方法可以使用户界面不被无限循环冻结?

谢谢!

方法ServerSocket.accept()是一种阻塞方法。这意味着 Socket s = ss.accept(); 停止当前线程,直到打开与服务器套接字的连接。

Swing 中的事件调度是单线程的,上面提到的 while 循环和阻塞操作将保持线程 'busy' 并阻塞与 UI.

的所有其他交互

您应该 运行 将整个 while 循环放在一个单独的线程中。当你想停止服务器时,你还应该确保退出while循环并线程完成执行。

Swing 是一个单线程框架,这意味着在事件调度线程的上下文中执行的任何阻塞或长 运行 操作都会阻止它处理事件队列,从而使您的应用程序挂起。

它也不是线程安全的,因此您永远不应尝试从 EDT 外部修改任何 UI 组件的状态。

查看 Concurrency in Swing and Worker Threads and SwingWorker 了解更多详情

public class ServerSocketWorker extends SwingWorker<Void, String> {

    private JTextArea ta;

    public ServerSocketWorker(JTextArea ta) {
        this.ta = ta;
    }

    @Override
    protected void process(List<String> chunks) {
        for (String text : chunks) {
            ta.append(text);
        }
    }

    @Override
    protected Void doInBackground() throws Exception {
        ss = new ServerSocket(1234, 3);
        while (true) {
            publish("\nEsperando conexiones...");
            Socket s = ss.accept();
            publish("\nConexión entrante: " + s.getRemoteSocketAddress());

            conexiones++;
            //System.out.println("Debug: conexiones SERVER: " + conexiones);
            MultiThread mt = new MultiThread(s, conexiones);
            mt.start();
            ///////////////////////////////////////////////////////////////
        }
    }

    @Override
    protected void done() {
        stopServer(); //??
    }
}

要启动它,您可以使用类似...

public void iniciarServer() {
    ServerSocketWorker worker = new ServerSocketWorker(textAreaToAppendTo);
    worker.execute();
}

举个例子