[java] threads

Started by
13 comments, last by mill-o 22 years, 5 months ago
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
_______________________ http://mill.3dfxsweden.net
Advertisement
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
thanks for the fast reply. i''ll give it a try right away.

______________________________
catch (SpellingException e) {}
_______________________ http://mill.3dfxsweden.net
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
_______________________ http://mill.3dfxsweden.net
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.
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

"There is no reason good should not triumph at least as often as evil. The triumph of anything is a matter of organization. If there are such things as angels, I hope that they're organized along the lines of the mafia." -Kurt Vonnegut
thanks a lot WayfarerX. the gui is responding now and the PogressMonitor is updating properly.

______________________________
catch (SpellingException e) {}
_______________________ http://mill.3dfxsweden.net
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.

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) {}
_______________________ http://mill.3dfxsweden.net
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.

This topic is closed to new replies.

Advertisement