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

时间:2016-10-05 16:12:33

标签: java swing concurrency swingworker

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

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

我的观察和想法: 我试图将他们的doInBackground()方法同步到一个锁,以确保在继续之前必须等待另一个完成他们的任务。问题是我能够(只是几次)看到swingworker_1完成了doInBackground()(当第二个工作人员正在同步块中等待时),但是swingworker_2的done方法能够被EDT调用在swingworker_1完成方法之前,即使swingworker_2完成了之后。我想在doInBackground()返回之前使用发布,这似乎总是有效,但可能是一个不好的做法,因为它似乎用于中间结果而不是最终结果?另一种可能性是在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。

1 个答案:

答案 0 :(得分:0)

如果您对正在连续运行的工作人员感到满意,那么如果您根据示例代码同步锁定,那么他们就会使用SwingWorkerdoInBackground()以外的任何其他功能和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);