14

I have a couple of questions with regards to Swing and using EDT for GUI updates. I just started reading on this stuff so I am a full beginner in this area:

  1. Which operations are required to run on the EDT? If they don't, is simply an Exception raised?
  2. Are there any specific times when we actually are on the EDT automatically?
  3. If we schedule a task using SwingUtilities.invokeLater we enqueue it to the current queue of GUI update tasks (the EDT) right?
  4. Accesses to the above queue I guess are synchronized, or some concurrent collection is used, but if I schedule two GUI update tasks, from two background threads, it is impossible to say which one will be added first? For instance, if Thread 1 FIRST submits a task of setting the text of a JLable to either "yes", and then, short time later, second thread comes along and submits task of setting that value to "no", are we guaranteed that the result will be "yes", or is it simply a matter of how these things are scheduled by the OS?
  5. How exactly does the SwingWorker ensure that done() method is run on EDT? It sets the following code:

      future = new FutureTask<T>(callable) {
                   @Override
                   protected void done() {
                       doneEDT();
                       setState(StateValue.DONE);
                   }
               };
    

so I was wondering whether FutureTask somehow makes sure that invokeLater is called?

Thanks for all your answers.

Keeley Hoek
  • 543
  • 4
  • 18
Bober02
  • 15,034
  • 31
  • 92
  • 178

4 Answers4

18
  1. A good rule is that all operations (access/updates/...) should happen on the EDT. There are a few exceptions mentioned in the javadoc (certain methods of certain classes), but they are so hard to remember that it is easier to stick to the 'do everything on the EDT' approach. Exceptions will not be raised (luckily, JavaFX fixed this shortcoming). You can use a custom RepaintManager to detect most of these violations: see this article.

  2. Everything triggered by the user is handled on the EDT. For example if the user clicks on a button, the actionPerformed of the corresponding Action or ActionListener will be called on the EDT.

  3. Correct

  4. The thing you schedule first will be executed first. The invokeLater call simply adds the Runnable at the end of the queue. Using invokeLater a second time a bit later will add this new Runnable after the previously scheduled Runnable.

  5. Take a look at the code for doneEDT

     private void doneEDT() {
         Runnable doDone = 
             new Runnable() {
                 public void run() {
                     done();
                 }
             };
         if (SwingUtilities.isEventDispatchThread()) {
             doDone.run();
         } else {
             doSubmit.add(doDone);
         }
     }
    
seanf
  • 6,504
  • 3
  • 42
  • 52
Robin
  • 36,233
  • 5
  • 47
  • 99
  • Two questions: 4. So it is the first thread that executes invoke later right? So it can be the case that OS will schedule the second background threads invokeLater call FIRST and the order will be messed up? 5. I still don't see how that achieves EDT. do Submit adds the Runnable to AccumulativeRunnable... – Bober02 Aug 06 '12 at 09:19
  • @Bober02 See the javax.swing.SwingWorker.DoSubmitAccumulativeRunnable runnable, which is executed on the EDT due to the use of the Swing `Timer`. For 4: yes, you will have to make sure that your one background thread schedules the runnable before the other thread schedules its runnable if you want to control the order – Robin Aug 06 '12 at 09:27
  • 1
    At some time, everything submitted to doSubmit() is run in the EDT. You don't have to care how and where it's done: this class has been tested, and it works as documented. – JB Nizet Aug 06 '12 at 09:28
  • @JBNizet For my own understanding, and better comprehension of Swing,m I want to get to the bottom of this. I see the picture now: in the Base class - AccumulativeRunnable, submit method, called from add, was simply using invokeLater on SwingUtilities. That is perfectly understandable by me. Now, the submit method has been overriden to schedule a `Timer`, which does not call SwingUtilities. Therefore, where is the call to dispatch a taks on EDT mnissing? – Bober02 Aug 06 '12 at 09:51
  • @Bober02 it is a Swing timer, which calls its `ActionListener`s on the EDT. The source code of that class shows this – Robin Aug 06 '12 at 10:03
8
  1. Basically, every time you use a Swing component or a model of a Swing component, it must be done in the EDT. If you don't, no exception will be raised. It could work, but it could also not work, have erratic behavior, corrupted data, etc.
  2. Every Swing event listener is called in the EDT. Basically, except the main method, every line of code of a Swing application is executed in the EDT by default, unless you explicitely start a thread, use a SwingWorker, or something like that.
  3. yes.
  4. Tasks submitted to SwingUtilities.invokeLater() are executed in the same order as the order they were submitted.
  5. Internally, it uses SwingUtilities.invokeLater() or a similar method. The FutureTask doesn't have anything to do with Swing. It's the SwingWorker that ensures that its done method is executed in the EDT. The doneEDT() method has the following comment: Invokes done on the EDT.
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
0

SwingWorker ensure that done() method is run on EDT via below code:

    Runnable doDone =
        new Runnable() {
            public void run() {
                done();
            }
        };
    if (SwingUtilities.isEventDispatchThread()) {
        doDone.run();
    } else {
        doSubmit.add(doDone);
    }

Actually it add the doDone variable into AccumulativeRunnable doSubmit,

See the source code of AccumulativeRunnable.java you will find there has a below code

protected void submit() {

SwingUtilities.invokeLater(this);

}

That's why swingworker ensure the method done() running on EDT

Junior
  • 1
  • 1
-1

1. In Java GUI applications, main() method is not long lived, after scheduling the construction of GUI in the Event Dispatcher Thread, the main() method quits...and Now its EDT's responsibility to handle the GUI.

2. So we don't need to start our app on the EDT, its automatically done.

3 Always keep the UI work on the UI thread, and Non-UI work on the Non-UI thread.

So Always keep your EDT thread, which is the GUI thread only for GUI work.

Eg:

public static void main(String[] args){
    EventQueue.invokeLater(new Runnable(){
          public void run(){    
            myframe.setVisible(true);
         }
     }
}

4. Create a separate Non-UI thread to handle that long time taking method.

5. You can simply use a Thread or use SwingWorker which is specially introduced into Java to sync the UI and Non-UI thread.

6. SwingWorker doesnt ensure that done() method is run on EDT, but sync the output of it to EDT thread, which is the GUI thread.

shuttle87
  • 15,466
  • 11
  • 77
  • 106
Kumar Vivek Mitra
  • 33,294
  • 6
  • 48
  • 75
  • 2
    For your point 6: see class javadoc of Swingworker: Event Dispatch Thread: All Swing related activities occur on this thread. SwingWorker invokes the process and done() methods and notifies any PropertyChangeListeners on this thread. – Robin Aug 06 '12 at 09:15