3

Standard scenario: User presses button and starts big task. EventThread creates SwingWorker to execute the task and get's on with life.

Now, since the big task is highly parallelizable, the first thing the SwingWorker thread does is to create a bunch of worker threads and farms the work out.

My question: Are the worker threads allowed to call SwingWorker#publish() to trigger a GUI update or is only the SwingWorker thread allowed to do so?

Thanks, Carsten

[Edit] Some pseudo code to make my use-case a bit clearer. The quesiton is basically: Is the code below OK? And what if I leave out waitForAllWorkerThreadsToFinish();?

public class MySwingWorker extends SwingWorker {

  class MyWorkerThread extends Runnable {
    void run() {
      while(!exitCondition) {
        doSomeWork();
        publish(progressUpdate);
        reEvaluateExitCondition();
      }
    }
  }

  public Void doInBackground() {
    createAndStartBunchOfMyWorkerThreads();
    waitForAllWorkerThreadsToFinish();
  }

  void process(List<V> chunks) {
    updateGuiWithProgress(chunks);
  }
}
Carsten
  • 4,204
  • 4
  • 32
  • 49

2 Answers2

2

There isn't any limitation on which Threads can call SwingWorker#publish().

  • Do you have a reference or other information to back this up? – Carsten Jul 07 '11 at 23:49
  • 1
    No, I just browsed the source code in Sun's JDK 1.6. The code does not put any limitations on the Threads that can call publish() and the main effect (adding chunks to the `sun.swing.AccumulativeRunnable`) is a synchronised operation. This is only applicable to Sun's JVM, but it would be peculiar to make this operation not Threadsafe in another JVM. –  Jul 08 '11 at 03:53
  • This fact isn't generally useful though. At least, I tried to publish() in a shutdown hook, and then slept for 500ms to give what I published time to get into the process() function. It didn't arrive. – Scott M Feb 12 '20 at 00:32
2

In general, no; publish() is intended to run on the background thread, which must itself synchronize all the results coming from the subsidiary workers. Fortunately, you have considerable latitude in designing how the background thread does this. For instance, this example uses CountDownLatch.

Addendum: waitForAllWorkerThreadsToFinish() looks like a good use case for CountDownLatch. MyWorkerThread definitely should not call publish() from a thread other than MySwingWorker without synchronizing access to any shared data. MyWorkerThread can update the GUI using invokeLater(), but the order won't be reliable.

Addendum: You asked the very practical question,

Do you have any reference for your answer, that [other] worker threads are not allowed to use publish()?

Memory Consistency Properties is a good summary. In effect, you would be calling publish() from multiple threads without synchronization. The results would be unpredictable.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Thanks for the answer. I think the CountDownLatch is not suitable in my case as the worker threads need to update the GUI often to display progress, not only when they are finished. Ideally they want to call publish() with some progress info that is then displayed in the GUI. – Carsten Jun 29 '11 at 06:30
  • It might help to update your question with more details about the nature of the workers' interdependence. – trashgod Jun 29 '11 at 06:37
  • I've elaborated above. Is there one overall progress indicator, or one for each thread? – trashgod Jul 04 '11 at 07:43
  • One overall progress monitor. The actual set-up is different but you can think of it something like the worker threads publishing log messages that are displayed in a text view. They will iterate the while loop many times and should update the text view once per iteration. I'll use invokeLater(), but do you have any reference for your answer, that worker threads are not allowed to use publish()? – Carsten Jul 05 '11 at 10:14
  • Good question; I've elaborated above. – trashgod Jul 05 '11 at 16:10
  • I'm not sure the reference is sufficient. While it is clearly relevant, it seems to me `publics()` could or could not be written in a way that avoids these problems. Often APIs add a note saying whether a class/method is thread-safe or not to indicate this; which does not seem to be the case for SwingWorker. So what I'm looking for as a reference is some official documentation saying it is or is not thread-safe, or some negative first hand experience, or some in-depth knowledge of how `publish` is implemented internally. – Carsten Jul 07 '11 at 23:48
  • The summary links to the JLS, which is dispositive. The only implementation I've examined relies on [`sun.swing.AccumulativeRunnable`](http://www.koders.com/java/fid015F8C12265B23677D76EAC82D16FBBAEE94E2D4.aspx), which also uses `invokeLater()`. You'll have to decide if the dependence is acceptable and document accordingly. – trashgod Jul 08 '11 at 01:26