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:
- Is querying a Swing model's state outside the EDT (strictly speaking) wrong?
- If not, how come?
- If yes, how do you handle it? By luck, or by some clever workaround? InvokeAndWait?