Which Swing component methods are thread safe?
Google taught me that at least those are threadsafe. Here's an overview for the case that the link get broken again:
JTextPane
replaceSelection()
insertComponent()
insertIcon()
setLogicalStyle()
setCharacterAttributes()
setParagraphAttributes()
JTextArea
insert()
append()
replaceRange()
JTextComponent
replaceSelection()
setText()
print()
getPrintable()
UndoManager
- All methods.
DefaultStyledDocument
insert()
setLogicalStyle()
setCharacterAttributes()
setParagraphAttributes()
StyleContext
addAttribute()
addAttributes()
removeAttribute()
removeAttributes()
reclaim()
AbstractDocument
render()
remove()
insertString()
createPosition()
PlainDocument
insertString()
HTMLDocument
setParagraphAttributes()
Is the Swing repaint() method still safe to use outside the EDT in Java 7+?
This is the official reference:
Swing's Threading Policy
In general Swing is not thread safe. All Swing components and related classes, unless otherwise documented, must be accessed on the event dispatching thread.
And the repaint
method does not "document otherwise".
To doubly reassure you that you do not need to look any further than an individual method's Javadoc for the definitive answer, see for example how a method's thread safety was documented in Java 6 Javadoc.
Update
Apparently, more clarification is needed as to the distinction between normative specification, descriptive technical articles, and details of any specific implementation. What the Javadoc states is this: there is no guarantee that repaint
is a thread-safe method. Incidentally, the often-discussed decision in Java 7 to remove the "thread-safe" designation from most of the Swing API was just that: a change in contract, not implementation.
The specific implementation of repaint
in OpenJDK 7 appears to be thread-safe, a fact which has nothing to do with guarantees given by the specification. Code which relies on the thread safety of repaint
or other methods is broken and is not guaranteed to behave properly on all Java implementations.
Swing Thread Safe Programming
Nothing theoretical about it. It's very practical. The SwingUtilities.invokeLater()
method guarantees that the code within the Runnable
will run on the Event Dispatch Thread (EDT)
. This is important because Swing is not thread-safe, thus anything related to the GUI (Swing
, etc.) needs to run on the EDT
. The EDT
is a "it happens whenever it happens" thread that makes no guarantees about the order in which things are executed. If the GUI code is executed within a background thread (say, within a SwingWorker
instance), then it can throw errors. I learned this the hard way: in my learning years, executing GUI-changing code within a background thread caused random, inconsistent RuntimeException
s that I couldn't figure out. It was a good learning experience (SwingWorker
has a doInBackground()
method for background tasks and a done()
method for EDT
tasks).
In the same way you don't want to execute GUI code on a background thread, you also don't want to execute large operations (database queries, etc) on the EDT
. This is because the EDT
is dispatching all of the GUI events so everything on the EDT
should be very short and sweet. You can easily see this with a JProgressBar
set to indeterminate.
This SSCCE should illustrate it nicely. Notice the motion of the JProgressBar
as method()
is called, once on a background thread and once on a EDT
thread.
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
/**
*
* @author Ryan
*/
public class Test {
public static void main(String args[]) {
JFrame frame = new JFrame();
JProgressBar jpb = new JProgressBar();
jpb.setIndeterminate(true);
frame.add(jpb);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
new Task().execute();
}
public static void method() { // This is a method that does a time-consuming task.
for(int i = 1; i <= 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
static class Task extends SwingWorker<Void, Void> {
@Override
protected Void doInBackground() throws Exception {
/* Executing method on background thread.
* The loading bar should keep moving because, although method() is time consuming, we are on a background thread.
*/
method();
return null;
}
@Override
protected void done() {
/* Executing method on Event Dispatch Thread.
* The loading bar should stop because method() is time consuming and everything on the Event Dispatch Thread
* (like the motion of the progress bar) is waiting for it to finish.
*/
//
method();
}
}
}
Hope this helps.
Java: Swing Libraries & Thread Safety
Never do long running tasks in response to a button, event, etc as these are on the event thread. If you block the event thread, the ENTIRE GUI will be completely unresponsive resulting in REALLY pissed off users. This is why Swing seems slow and crusty.
Use Threads, Executors, and SwingWorker to run tasks NOT ON THE EDT ( event dispatch thread).
Do not update or create widgets outside of the EDT. Just about the only call you can do outside of the EDT is Component.repaint(). Use SwingUtilitis.invokeLater to ensure certain code executes on the EDT.
Use EDT Debug Techniques and a smart look and feel (like Substance, which checks for EDT violation)
If you follow these rules, Swing can make some very attractive and RESPONSIVE GUIs
An example of some REALLY awesome Swing UI work: Palantir Technologies. Note: I DO NOT work for them, just an example of awesome swing. Shame no public demo... Their blog is good too, sparse, but good
How to initialize gui objects in a thread safe manner in java swing?
The second example is wrong. Swing components must be created and used from the event dispatch thread. See https://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html.
Quote from the javadoc:
Calls to an application's main method, or methods in Applet, are not invoked on the event dispatching thread. As such, care must be taken to transfer control to the event dispatching thread when constructing and showing an application or applet.
(emphasis mine)
If Swing models' getters aren't thread-safe, how do you handle them?
- No, not wrong, but as with any cross-thread communication you need to ensure you provide appropriate thread-safety mechanisms if you decide to do this (e.g. use of
synchronized
orvolatile
). For example I typically write my ownTableModel
implementations, typically sitting onList<X>
whereX
is my business object. If I intend for other threads to query the List I will make this a synchronizedCollection
. It's also worth noting I would never normally update theList
from other threads; only query it. - Because it's exactly the same situation as with any other multi-threaded application.
- I typically make the collection synchronized (see 1).
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.
Is JCheckBox.isSelected() thread safe?
No, it's not thread safe. Swing generally is not thread safe. You need to use invokeLater
. On the other hand, you can make the current thread wait until the task ininvokeLater
finishes:
private boolean isSelected(final AbstractButton button) {
if (SwingUtilities.isEventDispatchThread()) {
// a shortcut so the AWT thread won't wait for itself
return button.isSelected();
}
final AtomicBoolean isSelected = new AtomicBoolean();
final CountDownLatch latch = new CountDownLatch(1);
SwingUtilities.invokeLater(() -> {
try {
isSelected.set(button.isSelected());
} finally {
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return isSelected.get();
}
Related Topics
Remove Duplicates from Arraylists
Concurrent Threads Adding to Arraylist at Same Time - What Happens
Java 8: How to Work with Exception Throwing Methods in Streams
How to Get All Methods of a Class
Maximum Size of a Method in Java
Why Can't I Use \U000D and \U000A as Cr and Lf in Java
Why Would One Declare a Java Interface Method as Abstract
Are Thread.Sleep(0) and Thread.Yield() Statements Equivalent
How to Programmatically Inject a Java Cdi Managed Bean into a Local Variable in a (Static) Method
404 Error Redirect in Spring with Java Config
How to Find the Index of an Element in an Int Array
Tomcat 7 "Severe: a Child Container Failed During Start"
How to Add Close Button to a Jtabbedpane Tab
How to Extract Parameters from a Given Url
What Do Curly Braces in Java Mean by Themselves
No Idea Annotations Attached to the Jdk 1.8 (C:\...), Some Issues Will Not Be Found