Swing, thread safety, and accessors

Hello, I am trying to keep my application thread-safe (updating Swing things using invokeLater), but there are two things I wasn't sure about:

1. Is javax.swing.text.Document really thread safe? I think I read something that said it was. As in, can I blithely perform insertString on a Document (DefaultStyledDocument) obtained from a JTextPane, even without using invokeLater? When I tried using invokeLater with insertString inside I ended up with an application that froze the entire GUI.

2. I know I should put all mutate/update calls to Swing objects inside invokeLater, but do I have to do this for simple data accesses? For instance, I want to do the following:

final Document documentRef = myJTextPane.getStyledDocument();

If I were to do that with invokeLater, how can I go about it without running into problems? Since the variable is a local variable in the method, it has to be final, apparently.

Thanks a lot!

[993 byte] By [GTSchemera] at [2007-11-27 8:22:58]
# 1
Document is just an interface, but AbstractDocument uses a system of read/write locks to protect its contents. Since all the concrete Document classes descend from AbstractDocument, you shouldn't have to worry about concurrency issues.
uncle_alicea at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 2
Thanks, but how about things like getStyledDocument or isVisible that are called on Swing objects? In general, must even accessors be called only in the event dispatch thread?
GTSchemera at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 3

well... accessors are typically pretty safe to call from where ever you want, in that you're typically not going to get locks or anything, but you may run into issues with data consistency - even with methods commonly described as thread safe (not in your example, but in something like an vector). if this may be an issue in your code, you need to make sure you synchronize the appropriate calls as well.

edscholla at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 4
Yeah...and when I tried to synchronize a call that's when I random into the problem I mentioned. How can one return data from an invokeLater block?I feel like I'm missing something simple and obvious. :p
GTSchemera at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 5

um, how about synchronizing your calls by using synchronize, rather than invokeLater (which doesn' synchronize per se- it just executes the runnable asynchronously on the event dispatch thread)? ;D

use a synchronized statement:

synchronize(objectToSynchronize){

doSomething();

}

or a synchronized method:

public synchronized void doSomething(){

doSomething....

}

http://java.sun.com/docs/books/tutorial/essential/concurrency/syncmeth.html

edscholla at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 6
I could do that presumably -- the way it's working now seems to work, in fact. But synchronizing that way would be accessing Swing component methods from outside the event-dispatching thread, which is presumably the whole thing that I have to avoid. :(Thanks for the ideas
GTSchemera at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 7

I am under the impression you repeatedly call invokeLater. If you start your swing application like this: SwingUtilities.invokeLater(new Runnable() {

public void run() {

new YourMainClassHere().setVisible(true);

}

});

All that happens afterwards in YourMainClassHere and its sub-components will happen on the EDT unless explicitly placed otherwise. You don't have to touch the invokeLater method again - all updates to swing components etc. are already therein, and hence on the EDT.

What you need to be explicit about, are things that take some time and that are not swing component updates (like fetching big documents from the internet or from a database). And in those cases, you use SwingWorker.

Maybe you kn ew all this. I just had the impression from your other posts on this thread that you call invokeLater() over and over...

rebola at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 8

the idea isn't to avoid accessing swing component methods outside the event dispatch thread- the idea is to avoid doing it in a way that causes problems! :D

but back to your original, specific questions, getting the document and calling insertString on a defaultStyledDocument can be done from any thread because something like getStyledDocument or isVisible would have no effect on an event dispatch under way, and insertString is explicitly stated to be thread safe.

but the main point you need to understand is that your goal isn't to simply call all your swing methods from a runnable called from invokeLater.

edscholla at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 9

I could mess with SwingWorker, but the problem is that the code I'm writing is executing in its own thread that's handling incoming network data from a server. It needs to call something that does a getWhatever on a Swing component. So all I wanted to know was whether the one or two getWhatever calls happening in the other thread needed to be in the event thread, or in a SwingWorker, or whatever, since I can't quite think how to pass data back FROM one of those threads to the existing one.

Anyway, hopefully it's unnecessary as long as my program works. :P

Thanks for the reply!

GTSchemera at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 10

SwingWorker is written to handle those cases. It is a separate thread, but communicates easily with the EDT.

If your getWhatever methods are getUIComponents or the like, I guess you want them to execute on the EDT, but if they are getSomeTsuffFromADataBase, you want them not to. I find the documentation to be very clear on this point:

http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html

There is also a method to retrieve status updates chemin faisant, i.e. underways while the not-EDT thread is executing.

And here's the SwingWorker project home page:

https://swingworker.dev.java.net/

rebola at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 11

Thanks for the link, rebol. SwingWorker looks like way overkill when all I want is something on the lines of myJTextPane.isVisible()...unless I rework stuff. Maybe eventually.

I'm pretty sure I do need to use a SwingWorker to handle something else, though, so I'll have to dive in eventually.

GTSchemera at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 12

I agree, for isVisible(), it is overkill. But isVisible() is to be executed on the EDT. SwingWorker is a separate thread for time and CPU consuming tasks that do not regard the GUI.

So if you're having a SwingWorker class anyway, for doing other stuff, just pass the myJTextPane to your SwingWorker constructor. Then you can execute myJTextPane.isVisible() anywhere in your SwingWorker class.

rebola at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...
# 13
Sorry for so many replies!"But isVisible() is to be executed on the EDT."Does that mean it really SHOULD be executed there, and I need to go through my code and find some way to force that to happen and pass data back to another thread? :P
GTSchemera at 2007-7-12 20:11:47 > top of Java-index,Desktop,Core GUI APIs...