Multi-threaded Swing programming

The RPTools applications are written in Java. If you're interested in contributing to any project here by submitting patches to the source code, this is the forum to ask questions about how to do so. Please put the two-letter tool name abbreviation in your thread Title. To enter this group, go to the Usergroups page of your User Control Panel and join the Java Developer group.

Moderators: dorpond, trevor, Azhrei

Post Reply
User avatar
Azhrei
Site Admin
Posts: 12086
Joined: Mon Jun 12, 2006 1:20 pm
Location: Tampa, FL

Multi-threaded Swing programming

Post by Azhrei »

jfrazierjr wrote:Well, it looks like ObservableList is backed by an ArrayList, which maintains order. ZoneRenderer.getSelectedTokensList() appears to be the place where the sorting is performed from a quick glance. The questions remaining are a) is this the only place(probably) and b) why was the returned token list sorted in the first place??
There's a list of which classes are part of the Collections framework and why a programmer might choose each one here and clicking on the Overview link. That's a child page under the top-level Java 6 page.
I am by no means a java expert, but I believe a new macro function that creates a new thread will halt macro execution and allow for interaction with the UI, so I am playing around with that(using the toolbar button approach so you can "finish" that macro call and continue with the rest of the original macro. I hope to get that tested in the next few hours for a proof of concept.
Probably not. There are concurrency issues with updating the GUI on anything except the event handling thread. Because the Swing component library does not know about any of the application programmer's code it can't have concurrency checking built into it (no mutex locks, for example).

That means that the only safe place to put GUI code is on the event thread.

When the user clicks a macro button, it's the Swing JButton that responds to the click and fires off the AP's code (AP = application programmer). So for most GUI-related things, the code the AP writes is already on the event thread. But say that you start another thread. What happens when it tries to access some Swing component via that other thread -- while the event thread is already executing the same code!? Without concurrency controls (i.e. locking of data structures) it's possible (likely?) that the internal data will get corrupted or out of sync resulting in failure of the GUI components.

There are two ways around this. The first is SwingUtilities.invokeLater() which queues up a Runnable object at the end of the event handling queue so that when the current AP code is done and it returns to the Swing JButton component (for example), that code will returns to its parent, and so on. When the code gets all the way to the top of the stack, it'll check the event queue before returning to the OS and see that there's another event. In which case that code will be executed.

This allows a Runnable to be executed in a deferred manner on the Swing thread and this approach should always be followed for running AP code in the simple case. A more sophisticated approach is possible but it's not for the beginner. ;)

The other technique is SwingUtilities.invokeWait() which takes a Runnable and invokes it immediately, waiting for that code to finish before the calling routine completes. It is essentially the same as just calling a method directly -- except that it works properly even if the calling thread is not the event thread!

I typed in the above from memory and I may have missed some details, so don't take the above as gospel. ;)

There are other ramifications of writing a multi-threaded Swing application and I would strongly suggest reading through the Swing Tutorials on Sun's web site, in particular the tutorial dealing with multi-threaded apps. Of course. ;)

User avatar
jfrazierjr
Deity
Posts: 5176
Joined: Tue Sep 11, 2007 7:31 pm

Re: Multi-threaded Swing programming

Post by jfrazierjr »

Azhrei wrote:The other technique is SwingUtilities.invokeWait() which takes a Runnable and invokes it immediately, waiting for that code to finish before the calling routine completes. It is essentially the same as just calling a method directly -- except that it works properly even if the calling thread is not the event thread!
Yep, thats exactly what I had planed:

Code: Select all

EventQueue.invokeAndWait(new Runnable() {
        public void run() {
		//Activate the targeting mode until the user "exits" out of targetting mode
	}
// now that targeting mode has exited, we have a list of token names that were selected, along with any grouping information, so we can exit this function call and continue with the other functions in the macro.
}
I save all my Campaign Files to DropBox. Not only can I access a campaign file from pretty much any OS that will run Maptool(Win,OSX, linux), but each file is versioned, so if something goes crazy wild, I can always roll back to a previous version of the same file.

Get your Dropbox 2GB via my referral link, and as a bonus, I get an extra 250 MB of space. Even if you don't don't use my link, I still enthusiastically recommend Dropbox..

User avatar
jfrazierjr
Deity
Posts: 5176
Joined: Tue Sep 11, 2007 7:31 pm

Re: Multi-threaded Swing programming

Post by jfrazierjr »

Bummer... so, I think I have finally figured out that what would be needed is to generate a new thread for the macro execution context before the first line of the macro is parsed. Then, block/wait would probably be possible where it is not today since all of the macro execution code is also inside the GUI thread...

On a side note, this would also keep a long running macro from hosing the UI until it finishes I would expect. The various input functions(input, dialog,frame) would need to would need to then call SwingUtils.invokeLater(for dialog,frame) or SwingUtils.invokeAndWait(for input and my "function") to modify the GUI and keep it responsive.

Anyway, not something quick and easy... Perhaps I will slowly work on this over time and we can start with a base model for 1.4 or I can just branch my own code for my group once I figure out just exactly where the new thread needs to be (MacroManager, MaptoolLineParser, or somewhere there abouts...).
I save all my Campaign Files to DropBox. Not only can I access a campaign file from pretty much any OS that will run Maptool(Win,OSX, linux), but each file is versioned, so if something goes crazy wild, I can always roll back to a previous version of the same file.

Get your Dropbox 2GB via my referral link, and as a bonus, I get an extra 250 MB of space. Even if you don't don't use my link, I still enthusiastically recommend Dropbox..

Craig
Great Wyrm
Posts: 2107
Joined: Sun Jun 22, 2008 7:53 pm
Location: Melbourne, Australia

Re: Multi-threaded Swing programming

Post by Craig »

jfrazierjr wrote:Bummer... so, I think I have finally figured out that what would be needed is to generate a new thread for the macro execution context before the first line of the macro is parsed. Then, block/wait would probably be possible where it is not today since all of the macro execution code is also inside the GUI thread...

On a side note, this would also keep a long running macro from hosing the UI until it finishes I would expect. The various input functions(input, dialog,frame) would need to would need to then call SwingUtils.invokeLater(for dialog,frame) or SwingUtils.invokeAndWait(for input and my "function") to modify the GUI and keep it responsive.

Anyway, not something quick and easy... Perhaps I will slowly work on this over time and we can start with a base model for 1.4 or I can just branch my own code for my group once I figure out just exactly where the new thread needs to be (MacroManager, MaptoolLineParser, or somewhere there abouts...).
If you use invokeAndWait() on your code then that code would be running back inside the GUI thread which is what you were trying to avoid in the first place. So instead what you need to do is craft your dialog any GUI type manipulation you need to do done inside of a invokeLater() providing a callback for when the process is done. Clicking on on the ok button (or what ever it says) would then call your call back, but the catch is it is still running in the GUI thread. To get around this your macro thread would have to use wait() which will cause it well wait... Then the call back uses notify() which will then notify the waiting thread (assuming the wait() and notify() are on the same object) its time to stop waiting and continue processing.

This tutorial explains it better than I can here.

User avatar
Azhrei
Site Admin
Posts: 12086
Joined: Mon Jun 12, 2006 1:20 pm
Location: Tampa, FL

Re: Multi-threaded Swing programming

Post by Azhrei »

Yep, gotta love the Sun tutorials for covering the basics. The realities of writing application code often go beyond what Sun covers in their tutorials, but it's a good starting point.

And I think there's a false perception that it would be any faster. Let's say you want to do some processing (call it "A"), then put an Wiki: input() on the screen (call that "B"), then do some more processing (call this last part "C"). None of it can be effectively parallelized.

While doing A it's possible that the results are needed by B. And while B is on the screen it's not possible to continue with C for the same reason.

If it were possible to force all input()'s to be done first and all calculations to be done later, then the calculations could perhaps be parallelized without any help from the MTscript programmer. This would be similar to the optimizations done by compilers, such as loop unrolling or dead code removal. It would not be easy at all for MTscript since the syntax is checked as the code is being read, so there's no syntactic pass that could be used to gather information about the upcoming execution context.

I don't really see any practical way to do this. The only things that could be separate threads are callback functions and MTscript doesn't have that really (except perhaps in the form of the Wiki: execLink() and/or Wiki: macroLink() functions, but those aren't really callbacks so much as deferred execution; I don't think multithreading would help).

Post Reply

Return to “Java Programming Info”