Anyone who has done some serious Swing development has (hopefully) heard about the “single thread rule”:
Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread.
The rule is well explained in the classical threads and swing article.
SwingUtilities.invokeLater() is your friend, so this rule is not particularly difficult to follow. However, until a few minutes (read: some posts) ago, i wasn’t aware that the rule has changed in 2004:
To avoid the possibility of deadlock, you must take extreme care that Swing components and models are created, modified, and queried only from the event-dispatching thread.
It is the subtle difference between realized (setVisible(true), show(), or pack() has been called) and created. While it was totally fine to launch your UI like this:
public static void main(String[] args) {
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Hello World");
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
you are now required to create and show all swing components in the EDT (from the official sun swing tutorial):
public class HelloWorldSwing {
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add the ubiquitous "Hello World" label.
JLabel label = new JLabel("Hello World");
frame.getContentPane().add(label);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
I am a bit puzzled — can the real swing experts please stand up?
I was aware that we are told to do everything in the EDT, including component construction, but I still don’t do it out of habit.I also do recall the text components being blamed for the potential deadlocks, but I have never seen any error myself.It feels like the haze surrounding the topic is because potential bugs have been discovered and a couple of deadlocks have been produced without anyone getting any hard answers.The truth of the matter is that if sun say we should construct components in the EDT then we probably should. That’s ok because:1) Constructing a component having already constructed its model takes no time at all and you have up to 200ms (which is my baseline) of complete freeze before a user thinks the application is frozen (although it will feel slow to them)1a) Realising and painting a component for the first time was probably the expensive thing anyway and the previous rule said that already had to be in the EDT, so construction time is negligible.2) A common pattern that I use it to assert(SwingUtilities.isEventDispatchThread()) in every single public methods of my component’s API. That is a nice way to spot misuse of your swing components (especially in your libs), but when components are constructed outside the EDT these asserts will fail and as a result you will probably remove them. If the construct in EDT rule is forced you will keep them.3) From what people are saying, you’re not going to find the problem anyway – it’ll be your customer.4) Peoples’ arguments that it causes additional boiler plate is complete rubbish. Even at app construction time you needed to use the EDT to make the thing visible, so the boiler plate already existed. From that point on you are either inside the EDT or outside. If you’re inside then no boiler plate, if you’re outside you would have to use the EDT to realise the component anyway so that boiler plate already existed in your swing code that wasn’t constructing components inside the EDT.My answer as a swing expert is that I don’t know, but all arguments that I can think of point to following their advise and constructing in the EDT.
nj — thanks for sharing your thoughts!what i don’t quite understand is (4):”if you’re outside [the EDT] you would have to use the EDT to realise the component anyway”.i had the impression that the original “single thread rule” didn’t require the realization to happen in the EDT, it only said that all code that altered or accessed component state after the realization, was required to run in the EDT.in other words, calling setVisible(true) in the main thread used to be totally acceptable.
Sorry, I was having a brain freeze. No you don’t, but unless the result of your UI action is to launch a new Window, you will always need to use the EDT and therefore the boiler plate will already exists. Given my intense dislike of popup windows and dialogs in applications I almost always try to “change” the existing ui to accommodate the modified ui rather than to display a new window. Because of this, the boiler plate already exists in the vast majority of my swing code already. An example of this is painting a busy overlay on a component rather than popping up a busy dialog.