tags:

views:

124

answers:

3

Hi all,

Pretty sure all of these approaches will work, but I'd appreciate opinions on which is the best.

Consider for argument's sake the (unfortunate) scenario where you have UI changing code and reasonably intensive (average 500ms) logic code mixed and inseparable. all of the changing ui components are on the one panel.

01 new Thread(){
02  public void run(){
03 
04  for (int i = 0; i < 100; i++){
05   // some processing
06   doSomething();
07   // update some ui components
08   panel.doSomeUi();
09  }
10 
11  panel.revalidate();
12  panel.repaint();
13 
14 }}.start();

Which of the following 3 approaches would you choose and why?

  1. wrap all code in invokeLater
  2. call invokeLater inside doSomeUi() and then again for revalidate/repaint
  3. only use invokeLater for revalidate/repaint at end

For mine:

option 1 would hang the Event Processing Thread (EPT) while all of the processing occurs

option 2 would have overhead considerations with many new runnables being created and in special cases may cause the ui to update in a half complete state if components need some of the subsequent ui changes to be valid

option 3 would be the most efficient but may have some thread safety issues

keen to hear other opinions.

A: 

Did you read the Java Lesson: Concurrency in Swing and consider using Worker Threads. Also check the TumbleItem Example

The Lesson explicitly says:

Tasks on the event dispatch thread must finish quickly; if they don't, unhandled events back up and the user interface becomes unresponsive.

and

When a Swing program needs to execute a long-running task, it usually uses one of the worker threads

jitter
thanks, but that doesn't change much, essentially you're saying you'd use a utility class or many instances of a utility class to do the same thing... i haven't used SwingWorker because it's relatively new, but my understanding is that it's just a convenience class to encapsulate a two part task - processing+ui. right?
pstanton
+2  A: 

The doSomeUi () some should be wrapped in an invokeLater () and should trigger whatever repaint/redrawing is necessary -- the Swing UI thread will paint while you keep computing.

The overhead of creating a lot of short-lived Runnable's will be tiny on a modern VM, and shouldn't be an issue.

So, option 2 (with suggested modification) should be it. When writing multi-threaded code, slow and correct is always better than fast and randomly buggy.

Matthew Phillips
i'll accept this answer unless someone goes into a bit more depth...
pstanton
+1  A: 

First of I would get it running single threaded. As an integral part of that I would make sure I had good code (e.g. not extending Thread and JPanel), with good separation of "business" logic and UI, tests, etc. It might not be something impressive, but it is deliverable. Check that into version control. Then perhaps see if there is a small, hot section I can do in parallel.

There are extreme ways of approaching the problem of multithreading. With no shared state we can queue immutable action events out from the UI, and queue immutable update events back in to replace the UI copy of the model. Alternatively we can share state and be very careful with locking (I suggest the biggest locks that could possibly work - careful with callbacks).

It may be useful to note that you don't have to add listeners to every little thing. You can have coarse grain listeners and then rapidly scan through data structures for updates.

An important thing to note is that the actions the UI sends to the "business" model and the state updates in the reverse direction should be as decoupled as possible (i.e. run from SwingWorker).

Tom Hawtin - tackline
firstly, when did i mention extending JPanel? secondly, while your advice **sounds** good, i don't see how it relates the question. i've clearly stated that for arguments sake, good separation is impossible. maybe it's the question that is flawed but what i'm trying to get at is more the trade offs of locking the EDT for the whole process, locking the EDT many times during the process, or performing most of the UI tasks off the EDT and then 're-synchronizing' by repaint/validating on the EDT at the end.
pstanton
`panel.doSomeUi();` *suggests* extending `JPanel` to me. Perhaps `doSomeUi` is a stand in for some `JPanel` methods, but there are limited choices off EDT. If separation is "impossible", as I suggest in my first paragraph, the first order of business is to do the "impossible".
Tom Hawtin - tackline
ok i should have written doSomeUi(panel); it was meant to be a semi-sudo code eg that would suggest ui code within the scope of a single container.
pstanton