模态对话后 SwingWorker publish() 和 process(List) 乱序

SwingWorker publish() and process(List) out of order after Modal dialogue

在复杂的 Java 应用程序中,我扩展了 SwingWorker,因此我可以在后台处理从套接字读取数据。套接字提供了更新 GUI 所需的大量数据。

有一个特殊的警告 - 写入套接字的服务器以客户端所依赖的非常特定的顺序写入内容。将其视为发送术语的定义,然后发送术语的使用。如果应用程序没有首先获取定义,它会崩溃或显示错误数据。这不是问题,因为服务器很小心地做对了,而且套接字是 TCP,所以我得到了按顺序交付。很简单:我从 Worker.doInBackground 函数中的套接字读取数据,解析它并调用 publish()。在 Worker.process(List) 中,我按顺序遍历列表,处理套接字给我的东西。一切顺利。

一切都很好,除非服务器发送的内容说服客户端弹出模态对话框,这可能会在它发送的内容的早期发生。当model box up时,后台线程继续读取socket并调用publish(),这是意料之中的。但是 worket.process(List) (请注意,这是放置在模态对话框中的代码)开始被调用,其中的内容乱七八糟。它可能仍在处理最后一个传递给它的列表,并被处理模态框正在执行的任何事件递归调​​用。

我的笔记说在 process(List) 中做 GUI 的东西是可以的,而且只能在 process(List) 中。我认为在 doInBackground() 中执行 GUI 操作是不安全的。所以弹出一个对话框,我假设,需要在进程(列表)中发生。

有没有办法告诉对话框停止调用 doInBackground() 或 process()?在关闭该对话框之前,我不想或不需要 运行 任何内容。有没有更聪明的方法来完成我需要做的事情?服务器随时可以免费发送新内容,顺序总是很重要,所以我看不出什么时候可以安全地设置对话框。

我尝试同步,在对话框打开时持有锁,并在调用 publish() 之前让 doInBackground 在锁对象上等待。没有骰子 - 它们可能是同一线程的 运行,并且 java 锁是递归的。 (如果他们不这样做,对话框可能会挂起。)

我能想到一个可能笨拙的解决方法。我可以用序列号标记事物到达 doInbackground() 的顺序,并且在处理过程中)我可以重新发布我得到的任何序列号意外太高的东西。但是我可能会陷入一个紧密的循环,直到对话框被关闭 ("Item 1129 is too high. Republish. Item 1129 is too high. Republish...")

正确的方法是什么?

我不确定我是否 100% 理解您的问题(如果我的回答是 "offtopic",请告诉我),但我会强调这一部分:

Is there a way to tell the dialog box to stop calling doInBackground(), or process()? I don't want or need anything to run until that dialog box is dismissed.

使用锁变量是实现这一点的方法。看我的例子。 代码内的注释。

public class Worker extends SwingWorker<Void, String> {
    private JDialog dialog;

    public Worker() {
        dialog = new JDialog();
        dialog.setModal(true);
        dialog.setLocationByPlatform(true);

        //Plays no role but since there is no frame (icon in task bar)
        //you might not be able to terminate the program
        dialog.setAlwaysOnTop(true);
    }

    @Override
    protected Void doInBackground() throws Exception {
        int times = 0;
        while (true) { //Worker runs forever

            //If dialog is visible, just wait it until it is closed
            if (dialog.isVisible()) { //or dialog.isDisplayable()
                Thread.sleep(10); //Rest cpu
                continue;
            }
            //Here you read the data from server and you publish things to GUI - "process" method
            if (times == 5)
                publish("dialog");
            else if (times == 10)
                publish("exit");
            else
                publish("chunk");
            times++;
            Thread.sleep(500);
        }
    }

    @Override
    protected void process(List<String> chunks) {
        String chunk = chunks.get(0);
        System.out.println("Processing....:" + chunk);

        //A dialog requested
        if ("dialog".equals(chunk)) {
            dialog.setVisible(true);
            System.out.println("Dialog closed");
        }
        //Exit requested
        else if ("exit".equals(chunk)) {
            System.out.println("Ran process 10 times, exiting....");
            System.exit(1);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Worker().execute());
    }
}