java SwingWorker.doInBackground() must not access GUI elements - java

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.

Related

How to prevent Deadlock when updating Swing components using swing timers and invokeLater?

Can deadlock happen for an arbitrary synchronised method which updates some Swing components if the threads which call to this method all use Swing Timer or SwingUtilities.invokeLater() . I think that it will not be necessary to call invokeLater() inside Swing Timer tasks.
So I will have Some Swing timers and some observers that update my components. Observers all call invokeLater() and Swing Timers call my arbitrary method updateComponents() directly.
If it can still cause Deadlock, will invokeLater() make me sure that no deadlock will happen?
Actions triggered by the Swing Timer, as well as runnables submitted to invokeLater, are all executed sequentially on the Event Dispatch Thread, and as long as you don't involve invokeAndWait, no other thread is waiting for an action to complete. Therefore no deadlock can arise from this usage pattern alone. If you do encounter a deadlock, the cause will not be related to the EDT and its event processing.
You do not need invokeLater from within any event callback, which includes the one submitted to the Swing Timer, because they are already guaranteed to be called on the Event Dispatch Thread.

Java invokeAndWait?

This is a really simple question about the invokeAndWait thing from swing utilities. I have heard that it synchronizes code execution on a single thread, but I'm not sure. If so, should I use invokeAndWait to do that?
SwingUtilities.invokeAndWait(Runnable) will enqueue the Runnable on the Event Queue. This will allow the Event Dispatching Thread to execute the run method of the Runnable within the context of the Event Dispatching Thread.
invokeAndWait will not return until AFTER the EDT has finished executing the run method. This means it's a blocking operation.
invokeAndWait is used to re-sync code to the EDT, allowing it to execute updates to the UI within the Swing toolkit.
Unless you are trying to get you code to be executed on the EDT, no, you shouldn't use it for thread synchronization.

Dispatch a task from EDT to main?

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).

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 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.

Explain what the following code does?

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

Categories

Resources