Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating Swing component from another thread with invokeLater or SwingWorker

I'm developing a small app, which would have Swing GUI. App is doing IO task in another thread, when that thread finishes GUI should be updated acordingly to reflect thread's operation result. Class running in a (worker, non-GUI) has object passed to it in contructor which would be used for updating GUI, so I don't need to put GUI stuff in a non-GUI class, but rather pass object for updating GUI to that class. As I understand form reading here, (thread/swing) safe options for updating (changing) Swing GUI would be to use javax.swing.SwingUtilities.invokeLater(), javax.swing.SwingUtilities.invokeLaterWait() and/or javax.swing.SwingWorker() which basically are doing the same thing.

This all threading issue with Swing is a little confusing for me, and yet I need to use threads to do anything meaningful in GUI apps and not hung GUI while processing in EDT, so what interests me for now is this:

  1. Are invokeLater and invokeLaterWait like sending message to EDT and waiting for it do it when it finishes processing messages that were before that call?

  2. is it correct from Swing thread safety aspect, to do something like this:

    interface IUPDATEGUI {  
      public void update();  
    }  
    
    // in EDT/where I can access components directly    
    class UpdateJList implements IUPDATEGUI {    
      public void update() {    
        // update JList...    
        someJList.revalidate();    
        someJList.repain();    
      }    
    }    
    
    class FileOperations implements Runnable {  
      private IUPDATEGUI upObj;  
      List<File> result = new ArrayList<File>; // upObject is accessing this  
    
      public void FileOperations(IUPDATEGUI upObj) {
        this.upObj = upObj;
      }
    
      private void someIOTask() {
        // ...
        // IO processing finished, result is in "result"
      }
    
      public void run() {
        someIOTask();
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            upObj.update();  // access result and update JList
          }
        }; );
      }
    }
    

In case this isn't correct then how should this be done?

If I could, I would prefer to use invokeLater instead of SwingWorker if possible, because I wouldn't need to change my whole class and it's somehow more neat/distinct me (like sending a message in Win32 apps).

Thanks in advance.

like image 426
Mil Avatar asked Feb 11 '10 21:02

Mil


People also ask

How do you update Swing component from thread other than EDT?

You can use invokeAndWait() and invokeLater() to update a Swing component from any arbitrary thread.

What is the difference between InvokeAndWait and invokeLater?

1) InvokeLater is used to perform a task asynchronously in AWT Event dispatcher thread while InvokeAndWait is used to perform task synchronously. 2) InvokeLater is a non-blocking call while InvokeAndWait will block until the task is completed.

What is SwingUtilities invokeLater () used for?

An invokeLater() method is a static method of the SwingUtilities class and it can be used to perform a task asynchronously in the AWT Event dispatcher thread.

Why are swings not thread-safe?

Most Swing object methods are not "thread safe". This means that if those (non thread safe) method are invoked from multiple threads this could result in thread interference or memory consistency errors. Only thread safe methods can be safely invoked from any thread.


2 Answers

Using invokeLater() and invokeAndWait() passes the Runnable parameter into the queue awaiting execution in the EDT. So calling invokeLater() will cause the Runnable to execute in the EDT when the EDT is able to process the request. invokeAndWait() simply waits (in the calling thread) until this execution takes place.

Using SwingWorker is ideal if you want to do background tasks that notify the EDT either at the end of execution or in intermediate states. An example would be to pass the current progress of a process to a JProgressBar.

For your example it seems that SwingWorker is a better choice but if you don't want to change your code too much then calling invokeLater() when the process is done will be just fine.

like image 73
Savvas Dalkitsis Avatar answered Oct 04 '22 18:10

Savvas Dalkitsis


I'd recommend not using the invokeAndWait until java 7. I found a spurious wake-up on this method that can cause really painful bugs. For me it led to some really rare and hard to debug null pointer exceptions.

http://bugs.sun.com/view_bug.do?bug_id=6852111

It's fixed as of java 7 b77.

like image 35
reccles Avatar answered Oct 04 '22 19:10

reccles