开发者

How does a Java thread synchronize with invokeLater()?

I have a non-GUI thread that starts a JFrame using

java.awt.EventQueue.invokeLater(new Runnable() {

    public void run() {
        cardReadPunchGUI = new IBM1622GUI();  // instantiate
        cardReadPunchGUI.setVisible(true);
    }
});

Part of IBM1622GUI's constructor instantiates a "model" for itself, which my non-GUI thread needs access to:

cardReadPunch = IBM1622GUI.getModel();

What is the correct way for my non-GUI thread to synchronize with the new GU开发者_运维技巧I that's been "invoked later"? (Without synchronization, of course, IBM1622GUI.getModel() just tends to return null.)


Use

javax.swing.SwingUtilities.invokeAndWait(Runnable doRun);

instead.

Causes doRun.run() to be executed synchronously on the AWT event dispatching thread. This call blocks until all pending AWT events have been processed and (then) doRun.run() returns.


Id suggest you share an CountDownLatch initialized to 1 with both both the non-GUI and GUI threads.

The non GUI thread when it starts will call latch.await() which will put it in a blocked state.

The GUI thread will call latch.countDown() when it finishes its initialization after which the non-GUI thread will exit from the await call and both threads are synchronized.


Well, if you have access to it you could always move that particular logic outside of the Swing thread and onto the thread that calls invokeLater. There's nothing unsafe about doing what you're doing there off of the Swing thread, assuming the constructor for IBM622GUI is well behaved.

Other than that, you could make use of various other mechanisms.

  1. You could use invokeAndWait, as cgull beat me to saying.
  2. You could have the runnable set the value of a Future instead of a direct reference, and block on the main thread by calling the future's get method.
  3. You could have a CountDownLatch with a starting count of 1 which you await() on your main thread, and countDown() from the Swing thread.

There are many, many utilities to help with synchronization.


Typically you pass parameters to the Thread. Run the logic in the background. And then post back any modifications you need to do to any of those objects, or UI elements on the UI thread using SwingUtilities.invokeLater(). Typically I create a simple a utility that allows me to specify what should run on the background thread, and what should run on the UI thread. SwingWorker is something you could use although I find it extremely painful to use. Something simple like this:

new AsyncThread<Param,T>() {
   public T executeInBackground( Param param ) {
      // do something long running
      T result = // do something long running;
      return T;
   }

   public void executeOnUI( T result ) {
      // update the UI here, or modify the model, etc.
   }
}.execute( param );

AsyncThread would execute the executeInBackground() method on another thread. Then internally it would post back to UI thread using SwingUtilities.invokeLater(). Then executeOnUI would run on the UI thread. The execute() method could create a thread to run in background, handle exceptions, etc.

I'd let the GUI possibly kick off the thread, and let the GUI pass it's model, or whatever part it needs, to the thread. Instead of the other way around. That way you can have the UI give feedback about that background thread that's running. But, you can't let the background thread touch (write/modify/change) members of that model that the UI thread would be reading/writing too at the same time. So if you plan on modifying the model in response to the background thread, post it back to the UI thread to be safe.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜