Monday, August 12, 2013

Swing is not thread-safe in Java - What does it mean? Event Dispatcher, SwingWorker, Multithreading and Best Practices

Couple of my reader ask question, what does it mean by Swing is not thread-safe and How does it affect coding in Swing GUI application? This post is an effort to help those readers and several other programmers to understand Swing and thread-safety in a bit more detailed way. To keep it simple, let's revise what does it mean by being thread-safe? We say an object is thread-safe, if we can call it's method, which can change it's state, from multiple thread at same time. To give you an example, java.lang.String is a thread-safe class, which means you can call any method e.g. substring(), toUpperCase() or toLowerCase() from multiple threads. By the way, String is thread-safe because it's immutable. Let's come back to Swing now, Core part of Swing is made up of different GUI component e.g. JLable, JPanel, JCombobox etc. All these components are not thread-safe, which means you can not call methods of this components e.g. JLable.setText("new title") from any thread, other than Event Dispatcher Thread(EDT). In one word, Since Swing is not thread-safe, you can not update Swing components from any random thread, they are always updated using Event Dispatcher thread. This is in fact one of the most popular Java Swing Interview Question, with lot's of interesting follow-up e.g. If Swing is not thread-safe than how do you update components from other thread? and which methods of Swing API are thread-safe? etc. We will see answer of this question in next section.


How to update Swing Component from different thread

Why Swing in not thread safe in Java, Swing Worker, multithreading Since Swing is not thread-safe by design, it's designer did provide couple of utility methods in SwingUtilities class to update any Swing component from a thread other thread Event Dispatcher Thread. You can use invokeAndWait() and invokeLater() to update a Swing component from any arbitrary thread. As name suggest, invokeAndWait() is a synchronous, blocking method and blocks until GUI is updated, while invokeLater() is an asynchronous call and doesn't wait for GUI to be updated. By the way, both of these method make sure that Swing GUI components are updated in EDT thread only. Both of these method takes a Runnable object, which contains code to update GUI, as shown below :

SwingUtilities.invokeLater(new Runnable() {
  public void run() {
    JLable.setText("Update Title");
  }
}

to learn more about both of these methods and How to use them, See when to use InvokeAndWait and InvokeLater in Java.

Couple of times, Interviewer also ask about, how do you find, if a particular thread is Event Dispatcher thread or not? Well, if you are familiar with Swing API, they you may know that SwingUtilities provides isEventDispatchThread() method, which can be used to find out if current thread is Event Dispatcher thread or not. Another follow-up question is Why Swing is not thread-safe in Java? Well, this is on similar lines like why multiple inheritance is not supported in Java or Why Java doesn’t support operator overloading. It's the decision taken by there designer, at that time. Since making an API thread-safe takes a lot of work, and it's often based upon benefit you get. Since GUI screens are mostly updated in response of user action e.g. when user click a button, and since events are handled in the same Event dispatcher thread, it's easy to update GUI on that thread. It's very rare, when an update request for GUI comes from a different thread e.g. may be once a network request is complete or a file is loaded. In such cases, you can use either invokeAndWait(), invokeLater() or preferably SwingWorker class, which is designed to run these lengthy time consuming task in a separate thread and same time managing inter thread communication between worker thread and Event dispatcher thread. Since EDT thread is most important in Swing and responsible for listening event and updating GUI, you must not do any time consuming task on it, otherwise, you risk your application to become unresponsive or frozen. Another key thing to note, while using multi-threading in Swing development is that, not only GUI components but there model e.g. TableModel for JTable, must be updated in Event Dispatcher thread. One of the crucial difference between AWT and Swing is that AWT components are thread-safe

Summary

Here is summary of our discussion, which is also a list of Java Swing best practices in multithreading environment. When you use threads in Swing development, you risk of deadlock and frozen GUI. By following these simple rules, you minimize your chances of errors.

1) Since Swing components are not thread-safe, until any specifics mentioned in Javadoc, they must be created and modified from AWT Event Dispatcher thread.

2) Not only Swing components but also there model e.g. ListModel, TableModel must be modified from Event Dispatcher thread.

3) AWT Event Dispatcher thread is responsible for updating GUI and listening events, so don't block them by doing time consuming task there.

4) You can use java.awt.EventQueue's isDispatchThread() or SwingUtilities.isEventDispatchThread() to check if current thread is EDT.

5) Use SwingWorker to perform lengthy time consuming task in worker thread.
6) Use InvokeAndWait() and invokeLater() to update GUI components from threads other than Event Dispatcher thread.

That's all on Why Swing is not thread-safe in Java, more important what does it mean by Swing being not thread-safe. We have also touched base on Event Dispatcher thread, SwingWorker, invokeAndWait, and invokeLater. This is an extremely important topic from Swing development and Interview point of view. I have never seen a Java Swing Interview, without any question from threading.

4 comments :

Thasar said...

Hello Javin,
one thing that bugs me is your writing: you write "there" instead of "their", as in:
"not only GUI components but there model"(should be "their").
Apart from that "grammar nazi thingy" - yet another excellent article, keep up the marvellous work! :)

One question: could you please add answer to which operations in Swing are thread-safe, if there are any? If I understand correctly, only the EDT operations are thread-safe, right? Best regards!

Javin @ Parse String to int in Java said...

Hello Thasar, Apologies for that mate, had to review it more carefully. Regarding your questions, repaint() and revalidate() are thread safe methods in Swing API. You can call them from any thread.

Thasar said...

No need to apologies :) thank You for the answer, and once again ( I can't stress that enough) - excellent article(s)!

Anonymous said...

ALL your post are truly exceptional but is there is anyway i can download all these blogs and read as pdf or word doc.

Or is there is any index for this blog which can be used .. because all java blogs are tremendous ! hats off !

Post a Comment