【问题标题】:Starting ServerSocket on Java with User Interface(Swing) Freezes使用用户界面(Swing)冻结在 Java 上启动 ServerSocket
【发布时间】:2015-04-29 06:07:46
【问题描述】:

早安,

我有一个 ServerSocket 的无限循环,工作正常...问题是当我尝试使用按钮启动 ServerSocket 时。我的用户界面“冻结”什么都没有动,但是服务器已经启动并且很好,这里有一个 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 冻结而无法正常工作。

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

谢谢!

【问题讨论】:

  • Swing 是一个单线程框架,这意味着在事件调度线程的上下文中执行的任何阻塞或长时间运行的操作都会阻止它处理事件队列,从而使您的应用程序挂起。它也不是线程安全的,因此您永远不应该尝试从 EDT 外部修改任何 UI 组件的状态。查看Concurrency in Swing 和Worker Threads and SwingWorker 了解更多详情

标签: java swing loops freeze


【解决方案1】:

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

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

查看Concurrency in Swing 和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();
}

举个例子

【讨论】:

  • 感谢您的回答,我会尝试其中的一些代码。我发布的代码是扩展 JFrame 类的方法,所以我会找到统一两者的方法。问候!
  • 嗨,我正在实现这个但是我有一个问题,我的老师教我一个 void 方法没有返回值,现在 Eclipse 说:当我覆盖时添加返回语句“doInBackground”方法 D:为什么?
  • Void 和 void 不是(必然)相同的东西。如果 Eclipse 有问题,则将return null; 添加到方法的末尾
  • @Cizaquita 哈哈哈,这是一个不错的改变;)
【解决方案2】:

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

Swing 中的事件调度是单线程的,上面提到的 while 循环和阻塞操作将使线程保持“忙碌”并阻塞与 UI 的所有其他交互。

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

【讨论】:

  • 好的,非常感谢!我会尝试为服务器做一个单独的 UI 并尝试制作一个单独的线程。问候!
猜你喜欢
  • 1970-01-01
  • 2015-02-08
  • 2016-07-22
  • 2017-10-21
  • 1970-01-01
  • 1970-01-01
  • 2011-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多