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.)
Use
instead.
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 forIBM622GUI
is well behaved.Other than that, you could make use of various other mechanisms.
invokeAndWait
, as cgull beat me to saying.Future
instead of a direct reference, and block on the main thread by calling the future'sget
method.CountDownLatch
with a starting count of 1 which youawait()
on your main thread, andcountDown()
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:
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.
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.