How does a Java thread synchronize with invokeLater()?

删除回忆录丶 提交于 2019-12-11 03:05:48

问题


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 GUI that's been "invoked later"? (Without synchronization, of course, IBM1622GUI.getModel() just tends to return null.)


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


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.



来源:https://stackoverflow.com/questions/6921187/how-does-a-java-thread-synchronize-with-invokelater

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!