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
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.
No comments:
Post a Comment