[2 days left] What’s wrong with your cloud strategy? Learn why multicloud solutions matter with Nimble Storage.Register Now

x
?
Solved

Need help with muti thread gui

Posted on 2004-11-01
32
Medium Priority
?
216 Views
Last Modified: 2010-03-31
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
  }
0
Comment
Question by:Dawkins
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 12
  • 10
  • 6
  • +2
32 Comments
 
LVL 86

Expert Comment

by:CEHJ
ID: 12463645
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
 

Expert Comment

by:krispin
ID: 12463652
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
 
LVL 86

Expert Comment

by:CEHJ
ID: 12463676
>>in your run

Should really have said 'in your runSimulation'
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

Author Comment

by:Dawkins
ID: 12463944
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
 
LVL 86

Expert Comment

by:CEHJ
ID: 12464043
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
 

Author Comment

by:Dawkins
ID: 12464138
> 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
 
LVL 4

Expert Comment

by:lcwiding
ID: 12464292
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
 

Author Comment

by:Dawkins
ID: 12464820
> 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
 

Author Comment

by:Dawkins
ID: 12464843
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
 
LVL 4

Assisted Solution

by:lcwiding
lcwiding earned 300 total points
ID: 12464935
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
 
LVL 86

Expert Comment

by:CEHJ
ID: 12465176
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
 

Author Comment

by:Dawkins
ID: 12465207
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
 

Author Comment

by:Dawkins
ID: 12465245
> 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
 
LVL 86

Expert Comment

by:CEHJ
ID: 12465332
>>.  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
 
LVL 4

Expert Comment

by:lcwiding
ID: 12466447
>> 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
 
LVL 92

Expert Comment

by:objects
ID: 12467713
Use of the SwingWorker class mentioned in the above link is useful for running code in a seperate thread.

0
 
LVL 92

Accepted Solution

by:
objects earned 400 total points
ID: 12467737
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
 

Author Comment

by:Dawkins
ID: 12483774
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
 
LVL 92

Expert Comment

by:objects
ID: 12490434
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
 
LVL 86

Expert Comment

by:CEHJ
ID: 12491508
Don't forget to place any signal to the gui, having received any events on that listener, on the event dispatch thread
0
 

Author Comment

by:Dawkins
ID: 12495199
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
 

Author Comment

by:Dawkins
ID: 12495266
(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
 
LVL 86

Expert Comment

by:CEHJ
ID: 12495323
The Simulation class should have an addListener method, just as with guis and addActionListener
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 12495369
invokeLater would be used to do the actual update to a gui
0
 

Author Comment

by:Dawkins
ID: 12498480
>  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
 
LVL 86

Assisted Solution

by:CEHJ
CEHJ earned 300 total points
ID: 12498687
>>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
 
LVL 92

Expert Comment

by:objects
ID: 12499001
> 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
 

Author Comment

by:Dawkins
ID: 12504350
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
 

Author Comment

by:Dawkins
ID: 12506399
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
 
LVL 92

Expert Comment

by:objects
ID: 12508487
>  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
 
LVL 86

Expert Comment

by:CEHJ
ID: 12565888
8-)
0
 
LVL 92

Expert Comment

by:objects
ID: 12569511
(:
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

By the end of 1980s, object oriented programming using languages like C++, Simula69 and ObjectPascal gained momentum. It looked like programmers finally found the perfect language. C++ successfully combined the object oriented principles of Simula w…
Java Flight Recorder and Java Mission Control together create a complete tool chain to continuously collect low level and detailed runtime information enabling after-the-fact incident analysis. Java Flight Recorder is a profiling and event collectio…
Viewers learn about the scanner class in this video and are introduced to receiving user input for their programs. Additionally, objects, conditional statements, and loops are used to help reinforce the concepts. Introduce Scanner class: Importing…
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
Suggested Courses

656 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question