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
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.
You could use invokeAndWait, as cgull beat me to saying.
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.
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.
Related
This question already has an answer here:
Main purpose of SwingUtilities invokeLater
(1 answer)
Closed 5 years ago.
Can anybody show me an example of what will happen if we did not use the invokeLater() method in Java?
class FibComputer implements Runnable{
public void run(){
final int result = fib(47);
SwingUtilities.invokeLater(new Runnable(){
public void run(){
jlbFib.setText(String.valueOf(result));
I suppose, jlbFib is a JLabel, and the FibComputer is intended to be run on some thread different from the event dispatching thread.
The package description for javax.swing says:
All Swing components and related classes, unless otherwise documented,
must be accessed on the event dispatching thread.
The jlbFib.setText() call is such an access, so it's correctly wrapped in SwingUtilities.invokeLater(...).
If you don't do that, you risk running into any kind of thread-safety problems. Typically, in 90% of cases everything will look fine, sometimes the label won't get updated correctly, sometimes maybe your layout gets crumbled, or your GUI might even completely freeze.
From the Oracle docs, In Swing programs, the initial threads don't have a lot to do. Their most essential job is to create a Runnable object that initializes the GUI and schedule that object for execution on the event dispatch thread. Once the GUI is created, the program is primarily driven by GUI events, each of which causes the execution of a short task on the event dispatch thread.
Application code can schedule additional tasks on the event dispatch thread (if they complete quickly, so as not to interfere with event processing) or a worker thread (for long-running tasks).
An initial thread schedules the GUI creation task by invoking javax.swing.SwingUtilities.invokeLater or javax.swing.SwingUtilities.invokeAndWait .
Both of these methods take a single argument: the Runnable that defines the new task. Their only difference is indicated by their names: invokeLater simply schedules the task and returns; invokeAndWait waits for the task to finish before returning.
Coming to your point, I believe your application is swing application. If you didn't use the invokeLater method, then how you will create and initialize Runnable object, because by creating object for Runnable means your defining a new task, that is going to execute the run() method.
I've been reading a bit about concurrency (which gives me a headache).
I understand you can set a task to run on the EDT from the main thread using:
SwingUtilities.invokeLater
but can you set a task to run on the main thread from the EDT?
As in:
Thread mymainthread=Thread.currentThread();//<referring to the thread that initially kicks off public static void main
public void mousePressed(MouseEvent e){ //queue a task to run on mymainthread }
Can it be done? Is it a bad idea?
The other question on SO similiar to this (here) talks about creating a new thread but wouldn't it be safer and simpler to keep using the main if I was aiming for a single thread (+EDT) application? .......or maybe I've got this all wrong.
EDIT: What I should have explained: I wanted to create objects that would communicate with each other on the main thread (running in a slow loop) so I didn't want any of them be instantiated on a different thread, edt or otherwise.
but can you set a task to run on the main thread from the EDT?
I think you are confused on what EDT is. Swing and many other frameworks use a technique called thread-confinement.
In order to guarantee thread-safety, all actions are executed from a single thread. This thread in Swing is called Event Dispatcher Thread.
This thread has a queue and executes all tasks from that queue sequentially one at a time, at the same thread. This is why your tasks should be short in order not to block the UI.
So when you use EDT you are essentially passing a task to its queue from your thread and EDT will eventually execute it.
What you can do is put a task on the EDT queue which spawns a thread to be executed on separate thread. If you want to use your current thread for some reason as the background thread perhaps you could but why would you need that? The most straightforward way is just to submit a runnable to run as part of some background thread e.g. part of a pool
You can create your own event loop to do thread-confinement. This would allow you a separate single thread which would behave like the EDT. Be careful not to share [effectively] mutable objects between the two threads simultaneously.
Implementation can be as simple as a while loop with a BlockingQueue. You can go slightly higher level by getting an ExecutorService from java.util.concurrent.Executors.newFixeThreadPool(1).
I have to write a GUI application that uses RMI to keep consistent state across multiple clients.
Because the RMI calls will block, I put them in a separate thread from the GUI thread.
To push information to and from the GUI thread my first thought was to use a synchronized buffer.
But if I call a synchronized method on the Buffer, the GUI will freeze. If I don't use the synchronized keyword the Buffer won't be thread safe.
From the Java Docs:
It is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
Is there some other alternative that will make the buffer thread safe and not freeze the GUI.
One approach is to separate the model data from the view using the Model–View–Controller pattern, shown here, here and here. In the last example, the model evolves on a background thread and the view is periodically updated using a javax.swing.Timer. SwingWorker, illustrated here, is an alternative.
See if any of the objects in java.util.concurrent would do the trick. They offer more fine-grained control than synchronized.
For example, here's what you could do with a Semaphore:
In some shared class
public class Shared {
public final Semaphore mutex = new Semaphore(1);
}
In the RMI thread
// synchronizing with other clients...
// now we're at the critical section. Block until we have the lock
Shared.mutex.acquireUninterruptibly();
// update state
Shared.mutex.release();
// critical section over. Schedule an update on the GUI thread.
In the GUI thread
// if the critical section is free, check for updated state. Else, just wait
if (Shared.mutex.tryAcquire()) {
try {
// read state and update GUI
} finally {
Shared.mutex.release();
}
}
Here, the GUI thread is not guaranteed to see every single update, but if the RMI thread isn't constantly updating state it should work.
You have a number of approaches you could try.
You could fire an event from the RMI/read thread that can be used to notify the UI of changes. Just make sure that you only update the UI in the EDT.
You could use a SwingWorker to process the RMI requests in the background and the publish`process` methods to sync the results back to the client.
May be this is trivial, I am struggling to understand a simple documentation on SwingWorker.
Here is the copy pasted content
Workflow
There are three threads involved in the life cycle of a SwingWorker :
Current thread: The execute() method is called on this thread. It
schedules SwingWorker for the execution on a worker thread and returns
immediately. One can wait for the SwingWorker to complete using the
get methods.
Worker thread: The doInBackground() method is called on this thread.
This is where all background activities should happen. To notify
PropertyChangeListeners about bound properties changes use the
firePropertyChange and getPropertyChangeSupport() methods. By default
there are two bound properties available: state and progress.
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.
Often, the Current thread is the Event Dispatch Thread.
--
The worker thread is not the EDT, hence the code in doInBackground() must not access GUI elements. Is my understanding correct?
Background:
We have small code that uses SwingWorker but has doInBackground() createing FileChooser and calling setCurrentDirectory(). I suspect that is leading me exception almost same as http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6637181 ( 11-Closed, Not a Defect)
Yes. From a background thread - both regular threads and SwingWorker.doInBackground you must not modify the UI to avoid various trouble.
Instead, wrap the changes in a Runnable and have them executed in the EDT via SwingUtilities.invokeAndWait, SwingUtilities.invokeLater or - when using SwingWorker - via publish (from doInBackground). Within the process method of SwingWorker, which is executed by the EDT, you may access the GUI.
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
Personally, I find invokeLater and invokeAndWait easier to use for many situations. SwingWorker is okay for e.g. progress bars.
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
Please tell me what does the above code does actually. I am looking for line by line explanation. especially the first line and tell me why do we use that and in what scenarios we have to use this.
In this Example you see an anyonmous class that derives from Runnable. This anonymous class overrides the run method of the interface runnable. Then this anonymous class is instantiated and passed to the EventQueue.invokeLater method, which is a static method. This method appends the object into... well... the eventQueue. In the EvenQueue are many events, like keyboard events or mouse events or whatever. There is a Thread that continuesly polls data from this queue. Once that Thread reaches the anonymous class that was instantiated here, it will execute the run() method, which will instantiate an Object of class NewJFrame and set it to be visible.
The whole point of doing this this complicated is that the new JFrame().setVisible(true) part is not executed in the main thread, but in the event dispatching thread. In Swing you must execute all code that modifies the user interface in the event dispatching thread.
Single-Thread-Model and EDT
Most modern UI libraries adopt the single-thread-model. That means, all the manipulation upon UI components MUST be done on the same single thread. Why? That's because allowing UI components being updated from multiple threads will lead to chaos since most Swing object methods are not "thread safe". For simplicity, efficiency and robustness, single-thread-model is adopted.
In Swing, the very thread that serve the single-thread-model is called the Event Dispatching Thread, i.e. EDT. It is not provided by Swing. It is provided by Abstract Window Toolkit, i.e. AWT.
Worker thread vs UI thread
A non-trivial GUI application usually has many threads. In modern GUI application, there can be many worker threads to do dirty work, but there's only one UI thread (Swing calls it EDT) to update the GUI. Worker threads usually need to reflect their work progress in GUI, so they need to communicate with the UI thread about that. So how does this communication happen?
java.awt.EventQueue
The communication happens through a message queue model. The java.awt.EventQueue is the very class that provides a event queue globally. This global event queue serves as the communication channel to the EDT. EDT picks up messages from this EventQueue and update UI components accordingly. If some other part of your program wants to manipulate the UI, that part of code should call EventQueue.invokeLater() or EventQueue.invokeAndWait() to queue a message into EventQueue. EDT will process all the pending messages in the EventQueue and eventually get to the message.
the main thread
Your code snippet usually resides in the main() thread, the main thread can be viewed as some kind of a worker thread here. Only that instead of updating the GUI by posting messages to EventQueue, it initiates the GUI. Anyway, initiation can be viewed as a kind of work, too.
After the GUI is initiated, the main thread will exits and the EDT will prevent the process from exiting.
And another good explanation:
Java Event-Dispatching Thread explanation
An interesting article:
Multi-threaded toolkit, a failed dream?
This is a block of code that is instructed to execute at a later time (sometimes called a deferred). The inner class (new Runnable() {...}) is essentially allowing you to pass a block of code that will be run. The invokeLater method guarantees that the block of code will be run, but makes no guarantees of when. Sometimes it's not safe to have certain code run immediately, and its too verbose to do the multi-threading yourself. So Java provides this utility method to safely run the code. The code will be run very soon, but not until it's safe to do so.
The invokeLater call will put the specified runnable on a queue to be processed later. That is, the code inside the run() method will not have been run yet when the invokeLater method call returns.
There are two typical use-cases for this type of code.
The currently executing code is run in a background thread. Background threads cannot access most of the swing API. Read more here for the reason for this. If the current thread is already the UI thread there is no reason and the call can safely be removed.
The current block must be exited, ie the code reach the last brace. This may cause resources to be released and so on. This is not so common.
An anonymous class is passed as parameter to the invokeLater call. It is the same as this code.
private void foo()
{
java.awt.EventQueue.invokeLater(new JFrameCreator());
}
private class JFrameCreator implements Runnable
{
public void run() {
new NewJFrame().setVisible(true);
}
}
Source
The invokeLater() method takes a Runnable object as its parameter. It sends that object to the event-dispatching thread, which executes the run() method. This is why it's always safe for the run() method to execute Swing code.
-IvarD