Archived

This topic is now archived and is closed to further replies.

mill-o

[java] threads

Recommended Posts

mill-o    122
i'm in the process of learning swing so instead of just writing a GUI that doesn't do anything, i decided to write an application that actually does something. everything works great apart from that i don't know how to use threads. the thing is that one operation "freezes" the gui. i know this can be solved by using threads for the processor hungry operation, just not how. i have these classes: Main // doh GUI // the gui. extends JFrame Application // this is where the calculations are done (more classes, but these aren't important) Main creates a new Application. Application calls the GUI and when the user performs a certain action, a cpu hungry operation performs some calculations. I'd like to run this in a new thread instead of the main thread so that i won't lock up the GUI. any ideas how to implement this or where to find more information? i've checked java.sun.com, but i weren't able to adapt their examples to suit my needs. _______________________________ catch (SpellingException e) {} Edited by - mill-o on November 9, 2001 7:54:46 AM Edited by - mill-o on November 9, 2001 8:26:44 AM

Share this post


Link to post
Share on other sites
Prosper/LOADED    100
When the user click on a button, launch a thread (have a look to the Thread class in the JDK) that will do all the operations without blocking the whole GUI. You may need to disable some widgets until the operation is complete to prevent the user from launching too many threads.

Edited by - Prosper/LOADED on November 9, 2001 9:01:03 AM

Share this post


Link to post
Share on other sites
mill-o    122
ok.. now Application extends Thread, meaning that when I create a new Application I create a new thread? the GUI is still not updating. i even tried app.setPriority(app.MIN_PRIORITY), but that didn't help either. all that happened is that the task took ~20000 ms instead of ~8000 ms. you can see the code below:

  
if (returnVal == JFileChooser.APPROVE_OPTION) {
File foo = fc.getSelectedFile();
Application app = new Application(foo);
app.start();
createProgressMonitor();
while (!app.isDone()) {
progressMonitor.setProgress(app.getProgress());
}
output.append(app.getResult());
}

in Application all the job is done in the run-method, which I suppose is correct.

any ideas, anybody?

______________________________
catch (SpellingException e) {}

Edited by - mill-o on November 9, 2001 2:27:28 PM

Share this post


Link to post
Share on other sites
meZmo    122
If your goal is to update a progress bar while processing, u might wanna have a look at Class Observable and Interface Observer.

There''s also some articles/tutorials on java.sun.com/docs describing how to use them.

Share this post


Link to post
Share on other sites
WayfarerX    130
Well, you''re doing a couple of things wrong. First off, you are updating a swing component from the event dispatch thread (the thread that calls your event listeners). Always update Swing compoents from other threads. Do this by passing your progressMonitor to the new Application when it''s created, and update the monitor in the run method whenever appropriate.
This also removes the need for the while loop, letting the event dispatch thread go about its business (repainting components & the such) while you do the stuff in app.run().

  
if (returnVal == JFileChooser.APPROVE_OPTION)
{
File foo = fc.getSelectedFile();
createProgressMonitor();
Application app = new Application(foo, progressMonitor, ouput);
app.start();
}

// ... In Application.run()


public void run ()
{
// ... Load data or do calculations

progressMonitor.setProgress(getProgress());
// ... Load more data or do more calculations

progressMonitor.setProgress(getProgress());
//...

output.append(getResult());
}


Of course, if progressMonitor or output (or anything else for that matter) are shared between different threads, be sure to place locks around them so that 2 threads don''t modify each other''s data. Do a search for "synchronized" on Goolge or Sun''s Java site for more info.

"So crucify the ego, before it''s far too late. To leave behind this place so negative and blind and cynical, and you will come to find that we are all one mind. Capable of all that''s imagined and all conceivable."
- Tool

Share this post


Link to post
Share on other sites
mill-o    122
thanks a lot WayfarerX. the gui is responding now and the PogressMonitor is updating properly.

______________________________
catch (SpellingException e) {}

Share this post


Link to post
Share on other sites
c_wraith    122
quote:
First off, you are updating a swing component from the event dispatch thread (the thread that calls your event listeners). Always update Swing compoents from other threads.


This is exactly wrong... It creates MANY race conditions in your code. Anything that updates a GUI component from any thread other than the dispatching thread should use SwingUtilities.invokeLater(Runnable) to execute the updates in the GUI thread.

Share this post


Link to post
Share on other sites
mill-o    122
mkay, i tried that. Application now implements Runnable instead of extending Thread. Application is now called as can be seen below:


if (returnVal == JFileChooser.APPROVE_OPTION) {
createProgressMonitor();
output.setText("");
javax.swing.SwingUtilities.invokeLater(new Application(fc.getSelectedFile(), progressMonitor, output));
}


The GUI and the ProgressBar don''t update properly now. I guess I didn''t understand you totally..

______________________________
catch (SpellingException e) {}

Share this post


Link to post
Share on other sites
c_wraith    122
Yeah, you misunderstood...

Definately run the logic in a separate thread. However, when you need to update swing components from that thread, use SwingUtilities.invokeLater(Runnable) to update the swing components, and NOTHING else.

Like this:

  
// do some calculations


// update progress bar:

SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
progressbar.setValue(v);
progressbar.repaint();
}
});

// do more calculations, and probably loop back to up above



Unfortunately, that will take a small bit of fiddling to get to work properly, as the value v that the progress bar is being update with will either have to be final (in which case it will have to be declared and initialized right before the call to invokeLater), or it will need to not be a local variable.

Share this post


Link to post
Share on other sites
mill-o    122
okay.. i did as you suggested and it works, more or less. i wrote a class Progress which can be seen below.

      
class Progress {
private int progress;

public Progress() {
progress = 0;
}

public int getProgress() {
return progress;
}

public void incProgress() {
progress++;
}
}

// --------------------------------------------------------

// update progress, in the class that does the calculations

progress.incProgress();
SwingUtilities.invokeLater(new Runnable(){
public void run() {
progressMonitor.setProgress(progress.getProgress());
}
});


the thing is that now the whole task takes 17000 ms to complete instead of 8000 ms. is this the price i have to pay or i'm doing something wrong?



______________________________
catch (SpellingException e) {}

Edited by - mill-o on November 12, 2001 2:19:21 PM

Edited by - mill-o on November 12, 2001 2:19:37 PM

Share this post


Link to post
Share on other sites
c_wraith    122
The only thing I can think of is that you''re updating the progressbar a LOT... That''s the only reason that solution should be slower. If you''re updating the bar more than a few hundred times, I''d say it''s worth looking into updating it far less often.

Share this post


Link to post
Share on other sites
mill-o    122
hehe okay, sounds reasonable. the textfile i''m using to test the program with contains ~200000 lines of text and i''m updating the progress bar in a loop which loops for every line, in other words, 200000 updates

i''ll fiddle a little and post the new results later tonight

Share this post


Link to post
Share on other sites
Neophyte    595
If more than one thread accesses the same instance of your Progress-class you should also make the methods called synchronized.

-Neophyte

- Death awaits you all with nasty, big, pointy teeth. -

Share this post


Link to post
Share on other sites