JavaSwingText components and Document: "Thread-safe" methods


"Thread-safe" methods

"Thread-safe"

Some text methods are explicitly marked as "thread-safe". These are

JTextComponent: replaceSelection (overridden in JEditorPane, JTextPane)

JTextComponent: setText (overridden in JEditorPane)

JTextArea: insert, append, replaceRange

JTextPane: insertComponent, insertIcon, setLogicalStyle, setCharacterAttributes, setParagraphAttributes

AbstractDocument: render, remove, insertString (overridden in PlainDocument, DefaultStyledDocument), createPosition

DefaultStyledDocument: setLogicalStyle, setCharacterAttributes, setParagraphAttributes (overridden in HTMLDocument)

StyleContext: several

Possibly not supported by the Document

The specific Document need not support multithreading at all, i.e. it assumes all of its methods are only called from the event-dispatch thread.

This is explicitly allowed by the Document documentation, but no indication of that fact is provided with those text methods that are claimed to be "thread-safe". At the minimum level, the documentation should read:

"This method is thread-safe if the underlying Document is."

Usage of multiple Document modification methods without a write-lock inbetween

Not possible to call them in a (thread-)safe way because of arguments

Known weirdnesses of the Document locking mechanism make it impossible that these methods (except boundary cases) can be called in a thread-safe way at all: The arguments to "thread-safe" document methods.

No-one would consider (vector being a Vector, so its individual methods are "thread-safe", which is even more than can be said about Document.getLength())

vector.add(vector.size(), "whatever");

thread-safe without a synchronized (vector) { } around it, but the interface Document doesn't allow the write-lock equivalent of it, which would be:

{
    document.writeLock();
}
try
{
    document.insertString(document.getLength(), s, null);
}
finally
{
    document.writeUnlock();
}

Remarks on individual methods

setText

There are actually two ways setText operates:

In JTextComponent and then in JTextArea, JTextField, JPasswordField, it first removes the old text (Document.remove), then inserts the new (Document.insertString). This is not thread-safe because of a) the argument calculation for remove, b) the period between remove and insertString without a write-lock, during which another thread could insert.

In JEditorPane/JTextPane, the old "text" (but not the complete document structure) is removed (Document.remove), then EditorKit.read is used to read, interpreting the String argument as "externalized form". EditorKit.read is not even documented as thread-safe, and will use multiple steps of inserting without keeping a write-lock all of the time (definitely with the plain text default implementation, possibly in HTMLEditorKit) . Anything may happen if another thread changes the Document at the same time.

Anyway, because the fact that it does not/cannot really cleanup all of the old state, it is probably always better to read into an explicit new Document (that, if it is not shown, can probably be done safely in a background thread).

replaceSelection

Not on its own: It used Caret positions without ensuring these do not change etc.


(C) 2001-2009 Christian Kaufhold (swing@chka.de)