Need help with muti thread gui

Hi all,

I have a Gui which launches a simulation which runs in its own thread.  While the simulation is running, it displays a Gui showing its progress.  My problem is that because the simulation is extremely processor intensive the Gui displaying its progress takes ages to show itself.  

Here is the code, can anyone tell me any structural mistake I am making?

// Here is how it is called from the main GUI:

      Simulation simulation = new Simulation(simulationEcology);
      simulation.start();

// And here is class Simulation:

public class Simulation extends Thread implements ActionListener {

  public Simulation(Ecology ecology) {
    this.ecology = ecology;
    createAndShowGUI(); // creates a GUI displaying the simulation's progress.  
  }

  public void run() {    
    runSimulation();  // Very processor intensive
  }
DawkinsAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

CEHJCommented:
You need to ensure that any updates to the gui are made in the gui thread. In your case, in your run, you could do this by doing EventQueue.invokeAndWait, with a Runnable that updates the gui
0
krispinCommented:
I would imagine that if the method  "runSimulation();" is processor intensive there may be no way around it other than trying to make you method more efficient. Try remove a few variables (and re-using others, etc). Without seeing the code for the method I'd be unsure of what else to suggest
0
CEHJCommented:
>>in your run

Should really have said 'in your runSimulation'
0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

DawkinsAuthor Commented:
It isn't really *updates* to the Gui that are the problem - it's mainly just the fact that the Gui takes ages to *create* in the first place.  

By setting the simulation thread's priority to lowest it cures the problem - but I want it to have as much processor as possible so that it finishes as quickly as possible.

So maybe the solution is some sort of hack which sets the priority to lowest to allow the Gui to form, then after an arbitrary amount of time it increases the priority?  This doesn't seem like a good design to me though(?).
0
CEHJCommented:
Are you sure that the gui has been allowed to fully show itself in its initial state before the simulation thread has been started?
0
DawkinsAuthor Commented:
> Are you sure that the gui has been allowed to fully show itself in its initial state before the simulation thread has been started?

Nope that sounds like exactly the problem.  How do I check this or allow for it?
0
lcwidingCommented:
Without seeing the code for your main thread, it is hard to be more specific. But, one issue to consider is that Java uses a cooperative threading model, so other threads will not get time unless a thread gives the a chance. If your simulation thread is computational intense, I would recommend interspersing some calls to Thread.yield() within your loop to provide opportunities for other threads to jump in and run.

If it is just the initial display that you want to make sure appears quickly, you could try setting up either an initial sleep call before starting your main thread so that the UI has time to initialize, or set a flag that your UI code will set once it has initialized. Your simulaiton thread could set a wait on that flag, which the UI flag could then issue a notify to reawaken the simulation thread.
0
DawkinsAuthor Commented:
> or set a flag that your UI code will set once it has initialized

I tried this by changing a flag after the method createAndShowGui had finished, but it didn't work.  Even though my code had finished executing, the gui still hadn't appeared on screen.  My novice speculation is that although my setup code had finished, a separate thread actually handles the displaying of the graphics on the screen, and this was having trouble getting enough processor time?

If it helps, here is the main method:

  public static void main(String arguments[]) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    });
  }

The Gui created by createAndShowGUI() is the one which then creates the simulation thread.
0
DawkinsAuthor Commented:
Another point I should make - the reason this is such a problem is that I am setting the priority for the processor intensive thread to Thread.MAX_PRIORITY -1

I'm doing this because I want the simulation to run as fast as possible.. but maybe it isn't such a good idea..
0
lcwidingCommented:
As part of setting up the GUI, have you called repaint() on the container your UI is displayed in? After doing so, I would recommend a quick call the Thread.sleep(n), where n is 500 to 1000 to provide the system some time to perform the actual repainting.

Finally, I would also recommend that you place the Thread.yield() calls into your processing thread, so that the UI will get the occassional time slices needed for painting, and this includes for situations where a user might switch to another application, and so your app would need to repaint its window.
0
CEHJCommented:
You should create the gui on the main application thread

>>is that I am setting the priority for the processor intensive thread to Thread.MAX_PRIORITY -1

That's probably not such a good idea *at this point*.
0
DawkinsAuthor Commented:
ok I now create the GUI from within the simulation thread and put a sleep in as you recommended and it seems to work:

  public void run() {    
    createAndShowGUI();
    try {
      Thread.sleep(100);
    }
    catch (InterruptedException ex) {
    }
    runSimulation();
  }

I've also put Thread.yield() into the simulation loop :

private void runSimulation() {
    startTime = System.currentTimeMillis();
    while (ecology.getCurrentGeneration() < ecology.getNumberOfGenerations() && !isStopped && !isCancelled) {
    ....................... lots of calculations
    Thread.yield() ;
    }
}
0
DawkinsAuthor Commented:
> You should create the gui on the main application thread

I did have it like that but changed it after reading the tutorial where it says to put it into an invokelater when using the latest SDK.  I can't find the exact quote but this alludes to it:

http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html

"You have probably noticed that most of the tutorial's demos use a standardized main method that calls the SwingUtilities method invokeLater to ensure that the GUI is created on the event-dispatching thread. "
0
CEHJCommented:
>>.  I can't find the exact quote but this alludes to it

You're right - this is what they're saying:

"To avoid the possibility of thread problems, we recommend that you use invokeLater to create the GUI on the event-dispatching thread for all new applications"

That's a great pity, and another nail in the coffin for client-side Java
0
lcwidingCommented:
>> invokeLater

This is, IMHO, another reason to avoid Swing. But that is another discussion.

One thought on when you were using a flag to indicate that the UI had been generated, how did you implement that? My recommendation would be something like:

  public Object uiWait = new Object();

  public static void main(String arguments[]) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
        uiWait.notifyAll();
      }
    });

  public void run() {    
    try {
      uiWait.wait();
      Thread.sleep(100);
    }
    catch (InterruptedException ex) {
    }
    runSimulation();
  }

0
objectsCommented:
Use of the SwingWorker class mentioned in the above link is useful for running code in a seperate thread.

0
objectsCommented:
From a design perspective though, the implementation of your simulation and your gui should be seperate and thus minimising the types of problems you are running into. So your simulation should not worry about updating the gui, and instead the gui updates according to the current state of the sim.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
DawkinsAuthor Commented:
ok thanks for the help so far.  I've increased the points because I want to get into this in more detail!

-----
>>From a design perspective though, the implementation of your simulation and your gui should be seperate and thus minimising the types of problems you are running into. So your simulation should not worry about updating the gui, and instead the gui updates according to the current state of the sim.
-----
 
Hmm I don't understand how to do this.   My code for the simulation loop is below.  It updates the gui every iteration of the simulation loop.  It also can be paused via the Gui and have it's thread priority changed by the gui.  To do what you are suggesting wouldn't I need a separate loop running in the Gui thread to check for values set by the simulation thread?

private void runSimulation() {
    startTime = System.currentTimeMillis();
    while (ecology.getCurrentGeneration() < ecology.getNumberOfGenerations() && !isStopped && !isCancelled) {
      if( (this.getPriority() != threadPriority) ){
        this.setPriority(threadPriority);
      }

      ecology.playGeneration();
      progressBar.setValue(ecology.getCurrentGeneration());
      progressBar.setString("Generation: "+ecology.getCurrentGeneration()+" / "+ecology.getNumberOfGenerations());
      lastCheckedTime = System.currentTimeMillis();
      long timeTakenToDoChunk = lastCheckedTime - startTime;
      float progress = (float)ecology.getNumberOfGenerations() / (float)ecology.getCurrentGeneration();
      long estimatedTotalTime = Math.round(progress * timeTakenToDoChunk);

      timeRemainingLabel.setText(TIME_REMAINING_TXT +
                                 millisecondsToTime(estimatedTotalTime - timeTakenToDoChunk));
      while (isPaused) {
        synchronized (this) {
          try {
            wait();
          }
          catch (InterruptedException ex) {
          }
        }
      }
      Thread.yield();
    }
    this.setPriority(NORM_PRIORITY);
    if(isCancelled != true) {
      ecology.setNumberOfGenerations(ecology.getCurrentGeneration());
      Sounds.playEnd();
      ViewResultsFrame resultsGUI = new ViewResultsFrame(ecology);
      resultsGUI.show();
    }
    frame.dispose();
  }
0
objectsCommented:
Define a listener that includes methods required to notify of events of interest during the simulation.
For example something like:

public interface SimulationListener
{
   public void progress(Simulation sim, Ecology eco, long timeTaken, long totalTime);
   public void paused(Simulation sim, Ecology eco);
   public void resumed(Simulation sim, Ecology eco);
   public void loop(Simulation sim, Ecology eco);
}

The your sim class would then call the listener(s), instead of updating the gui.
And you would have a listener that would handle updating the gui, removing any coupling between the sim and the gui.
0
CEHJCommented:
Don't forget to place any signal to the gui, having received any events on that listener, on the event dispatch thread
0
DawkinsAuthor Commented:
Ok, before I try this could you just check I'm on the right track?  Am I right in thinking I would have a new class like this:

Class SimulationGUI implements SimulationListener

And then pass a reference to the SimulationListener interface into the Simulation class like this:

Class Simulation extends Thread {
  public Simulation(SimulationListener gui) {}
public void run() {
}
}


0
DawkinsAuthor Commented:
(Didn't mean to submit... )

Then every loop in the Simulation I put an event on the event dispatch thread like this:

    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            gui.progress(Simulation sim, Ecology eco, long timeTaken, long totalTime);
        }
    });

0
CEHJCommented:
The Simulation class should have an addListener method, just as with guis and addActionListener
0
CEHJCommented:
invokeLater would be used to do the actual update to a gui
0
DawkinsAuthor Commented:
>  The Simulation class should have an addListener method, just as with guis and addActionListener

Surely the simulation *gui* should have the listener shouldn't it?  Because it's listening for changes in the simulation loop?

I'm getting more confused here :).   Would someone be able to just give a 1-2-3 set of steps for separating the Gui out of the simulation?  I'm not even sure of step 1:

1)  Create a new class SimulationGUI.  Put all gui creation stuff in here (including event handlers for the pause button? Or do I put the button event handlers into the Simulation class?)
0
CEHJCommented:
>>Surely the simulation *gui* should have the listener shouldn't it?  

Yes, but the Simulation has the addListener method. Think of it as adding an actionListener to a button. The gui has the listener with actionPerformed, but the button itself has the list of listeners which is added to by addActionListener

1) should be one of the last steps. You need to do the listening stuff first
0
objectsCommented:
> Surely the simulation *gui* should have the listener shouldn't it?

no it *is* the listener, ie. your gui (or whatever class is used to control it) implements SimulationListener

> Would someone be able to just give a 1-2-3 set of steps for separating the Gui out of the simulation?

Create a Listener interface for your sim class, adding methods to add/remove listener (for simplicity you could initially just support a single listner). Also add code to fire the relevant event when they occur.

Create a listener implementation that updates the gui appropriately accordingly.
0
DawkinsAuthor Commented:
ok I'm trying to implement your suggestions.  I still have a major question about how the gui is going to send events *back* the other way to the Simulation (to pause it etc).  But anyway,  here's what I've done so far could you tell me if this is what you meant?:

1) There's now 3 classes to replace the single original class Simulation:

--------code-----------
Class Simulation extends Thread

Class SimulationFrame extends JFrame  implements SimulationListener, ActionListener, ChangeListener, ItemListener

Interface SimulationListener
--------/code---------

2) I've added a the SimulationListener to the Simulation like this:

--------code-----------
Class Simulation extends Thread{
  Ecology ecology;
  SimulationListener simListener;

  public Simulation(Ecology ecology, SimulationListener listener) {
    this.ecology = ecology;
    this.simListener = listener;
  }
--------/code---------

3) Then I send events from within the run() method like this:

--------code-----------
  public void run() {
    while(.....) {
      ........... // run iteration
      final long timeLeft = estimatedTotalTime - timeTakenToDoChunk;
      javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            simListener.progress(timeLeft);
        }
     }
--------/code---------
0
DawkinsAuthor Commented:
Well the above seems to work even if I have got the wrong end of the stick with the design!

But it only works one way.  How do I get the Gui to send information back to the simulation?  

My current guess is to do the reverse of the above:  make a new interface called "SimulationGuiListener which the Simulation can implement with methods such as "pause()" and "changeThreadPriority()" and communicate via that.  

Can anyone confirm this as being stupid?
0
objectsCommented:
>  I still have a major question about how the gui is going to send events *back* the other way to the Simulation (to pause it etc).

You would simply call the Sum method that performs the required action
eg. if you want to pause call it's pause() method (or whatever it may be called)

no listener interface required here


0
CEHJCommented:
8-)
0
objectsCommented:
(:
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.