如何确保两个并发 swingworker 的 done() 方法在 EDT 中以正确的顺序执行?

How to make sure the done() method of two concurrent swingworkers is executed in EDT in the right order?

您好,我一直在尝试学习如何使用 SwingWorker 来更新 swing 应用程序的 GUI。

我的问题是:如果我有 2 个可以同时 运行 的 swingworker(每个都从不同的按钮触发)如何确保在 EDT 中调用他们的 done 方法(更新gui) 他们被解雇的顺序相同吗?

我的观察和想法: 我试图将他们的 doInBackground() 方法同步到一个锁,以确保一个必须等​​待另一个完成他们的任务才能继续。问题是我已经能够(只是几次)看到 swingworker_1 完成 doInBackground() (而第二个工人正在同步块中等待),但是 swingworker_2 的 done 方法能够在 swingworker_1 的 done 方法之前被 EDT 调用,即使 swingworker_2 在之后完成。我考虑过在 doInBackground() returns 之前使用 publish,这似乎总是有效,但可能是一种不好的做法,因为它似乎用于中间结果而不是最终结果?另一种可能性是在 doInBackground() 中使用 SwingUtilities.invokeLater 在返回之前更新 gui,我担心这也可能是一个不好的做法。提前致谢。

我使用的测试,按下第一个按钮然后立即按下第二个:

    //Code that runs in the first button
    SwingWorker<Void, Void> swingworker = new SwingWorker<Void, Void>() {

        @Override
        protected Void doInBackground() throws Exception {
            synchronized (lock) {
                System.out.println("Thread 1");

                Thread.sleep(1000);
                return null;
            }

        }

        @Override
        protected void done() {

            System.out.println("Done with thread 1 ");
            //update GUI    
        }

    };
    swingworker.execute();



    //Code that runs in the second button
    SwingWorker<Void, Void> swingworker = new SwingWorker<Void, Void>() {

        @Override
        protected Void doInBackground() throws Exception {
            synchronized (lock) {
                System.out.println("Thread 2");

                return null;
            }

        }

        @Override
        protected void done() {
            System.out.println("Done with thread 2 ");
            //update GUI
        }

    };
    swingworker.execute();

更新: 只是为了澄清,我不关心谁先开始(swingworker_1 或 swingworker_2),这取决于按下哪个按钮第一的。我想保证的是,如果来自按钮的工作人员是第一个执行的(并因此在工作人员在 doInBackground() 方法中同步时完成)那么它也应该是第一个排队更新 EDT 中的 gui .我发现即使工作人员同步,这也不一定会发生,有时稍后启动任务的工作人员仍然设法在第一个任务之前更新 gui。

如果您对工作人员 运行ning 串行表示满意,如果您根据示例代码在锁上同步,并且您没有使用 SwingWorker 的任何其他功能,他们就会这样做除了 doInBackground()done(),使用单线程执行器和 SwingUtilities.invokeLater(...) 在 GUI 上显示结果可能更容易。

这样,您可以保证提交给执行者的东西将 运行 按照提交的顺序排列。

如果这对你有用,你可以尝试这样的事情:

final ExecutorService executor = Executors.newSingleThreadExecutor();

// Code that runs in the first button
Runnable worker1 = new Runnable() {
  @Override
  public void run() {
    System.out.println("Thread 1");
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace(System.err);
    }
    SwingUtilities.invokeLater(this::updateGUI);
  }

  private void updateGUI() {
    System.out.println("Done with thread 1");
    //update GUI
  }
};
executor.execute(worker1);

// Code that runs in the second button
Runnable worker2 = new Runnable() {
  @Override
  public void run() {
    System.out.println("Thread 2");
    SwingUtilities.invokeLater(this::updateGUI);
  }

  private void updateGUI() {
    System.out.println("Done with thread 2");
    //update GUI
  }
};
executor.execute(worker2);