It is well known that updating a Swing GUI must be done exclusively in the EDT. Less is advertised that reading stuff from the GUI must/should also be done in the EDT. For instance, let's take ButtonModel's isSelected() method, which tells (for instance) ToggleButton's state ("down" or "up").
In every example I've seen, isSelected()
is liberally queried from the main or whichever thread. But when I look at DefaultButtonModel's implementation, it's not synchronized, and the value is not volatile. So, strictly speaking, isSelected()
could return garbage if it's read from any other thread than the one from which it's set (which is the EDT, when the user pushes the button). Or am I mistaken?
I originally thought about this when shocked by item #66 in Bloch's Effective Java, this example:
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while(!stopRequested) i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
Contrary to what is seems, that program never terminates, on some machines at least. Updating the stopRequested
flag from the main thread is invisible to the background thread. The situation can be fixed with synchronized getters & setters, or by setting the flag volatile
.
So:
Most Swing object methods are not "thread safe". This means that if those (non thread safe) method are invoked from multiple threads this could result in thread interference or memory consistency errors. Only thread safe methods can be safely invoked from any thread.
Many important methods of Swing components are explicitly documented as threadsafe. These include the JComponent repaint() and revalidate() methods, many methods of Swing text components, and all listener add and remove methods.
When Thread 1 accesses the method at t1, Thread 2 may not be done with the method. So the value returned to Thread 1 is the value that has not been increased. Adding synchronized to this method will makes it thread-safe. When synchronized is added to a static method, the Class object is the object which is locked.
If you want to make sure your bean is thread-safe, you should go for the @RequestScope. As the name suggests, Spring binds such bean to a particular web request. Request beans aren't shared between multiple threads, hence you don't have to care about concurrency.
synchronized
or volatile
). For example I typically write my own TableModel
implementations, typically sitting on List<X>
where X
is my business object. If I intend for other threads to query the List I will make this a synchronized Collection
. It's also worth noting I would never normally update the List
from other threads; only query it.Caveat
Despite my answer above I typically do not access models directly outside of the EDT. As Carl mentions, if the action of performing an update is invoked via some GUI action there's no need to perform any synchronization as the code is already being run by the EDT. However, if I wish to perform some background processing that will lead to the model being changed I will typically invoke a SwingWorker
and then assign the results of doInBackground()
from within the done()
method (i.e. on the EDT). This is cleaner IMHO as the doInBackground()
method has no side-effects.
Yes it is wrong; unless both threads synchronize on the same object or use some other memory barrier, like volatile, as defined by the JMM one or the other can observe inconsistent memory contents. Period. End of story. Violating this might work on some, even many, architectures, but it will eventually bite you on the hiney.
The problem here is that with a few exceptions where you provide the model, such as what Adamski referred to, the Swing code is not going to synchronize on anything.
And it's worth noting that the JMM (Java Memory Model) has changed with JSR-133 in Java 5 in very important ways, so behavior with a J4 and earlier JVM may well yield different results than J5 and later. The revised JMM is, as you would expect, considerably improved.
Swing is in general not only not thread-safe, but thread-hostile. However, most models, other than Swing text, are thread-agnostic. This means that you can use models in any thread, provided you use standard thread protection. Swing text was an attempt to be thread-safe but failed, and is in fact thread-hostile. Only use Document
s from the Event Dispatch Thread (EDT).
The usual advice is to run potentially long running (typically blocking) tasks off the EDT. However, threading is difficult. SwingWorker
is a popular way to induce bad design - avoid it. Try to keep EDT and non-EDT code separated. Try not to share mutable state.
Threading bugs are difficult. You might not see them on your machine, but customers may well do. Perhaps bugs appear due to optimisations in later versions of the JRE. Thread bugs are difficult to track. Therefore, be conservative. Even blocking the EDT briefly is better than nasty bugs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With