views:

496

answers:

5

I want a thread to execute in the background every 500 milliseconds. To do that, I extended a Thread, implemented ActionListener and put the class that I extended into a Timer. The Timer calls run() every 500 milliseconds. However, my whole Swing GUI freezes up when this thread is downloading stuff from the Internet. I want it to run in the background, without freezing up the GUI while it waits for IO to finish. I also the downloader to finish downloading before we wait 500 milliseconds.

gogogo() is called to initialize the whole process:

public final class Downloader extends Thread implements ActionListener
{
public static void gogogo()
{
 t= new Downloader();
 new Timer(500, (ActionListener) t).start();

}

public void run() 
{
 doStuff(); //the code that i want repeatedly called
}

public void actionPerformed(ActionEvent e) 
{
 run();
}
}
A: 

Hmm, most likely all you need to do is reduce the thread priority, so it doesn't eat all your resources.

Aistina
Its not lagging. Its blocking the GUI from running.
Penchant
+1  A: 

Instead of using the swing timer try using the java util timer or the ScheduledExecutorService. the swing timers share a pre-existing timer thread and that may be causing the freezing.

A recommendation from the java tutorial:

In general, we recommend using Swing timers rather than general-purpose timers for GUI-related tasks because Swing timers all share the same, pre-existing timer thread and the GUI-related task automatically executes on the event-dispatch thread. However, you might use a general-purpose timer if you don't plan on touching the GUI from the timer, or need to perform lengthy processing

jassuncao
A: 

You need to start the thread on each timer action. Calling the thread's run() method does not start the thread.

public void actionPerformed(ActionEvent e) 
{
        //run();
Downloader t = new Downloader();
t.start();

}

Might be better to use an anonymous class for the actionlistener. Excuse my java syntax but I have not verified it...

  new Timer(500, 
      new ActionListener(){
            public void actionPerformed(ActionEvent e) 
            {
               //run();
               Downloader t = new Downloader();
               t.start();

            }
          }).start();

Or without the timer...

public static void gogogo()
{
        t= new Downloader();
        t.start();

}

public void run() 
{
    while(true){
        doStuff(); //the code that i want repeatedly called

        Thread.sleep(500);
    }
}
dotjoe
What if I only want one downloader to download stuff at one time?
Penchant
Then I would make the downloader sleep between iterations. The reason your GUI was freezing is because the thread was never started...
dotjoe
+5  A: 

Just start the thread once, make it loop, and do Thread.sleep(500L) with each iteration. That probably makes more sense that starting a brand new thread every 500ms. No reason to incur the associated cost if you can avoid it.

Willie Wheeler
I feel really really dumb. :)
Penchant
No way dude. You're getting into the fun stuff. Wish more developers would. :-)
Willie Wheeler
Well, I remember that I used a while loop to make thread go on in another program. I dunno why i forgot it. :)
Penchant
A: 

If your GUI is freezing up, then your lengthly task (doStuff) is probably running on the Event Dispatching Thread. While it hogs that thread, other actions can't use it.

If you're trying to run a task repeatedly, you may be better off with the TimerTask class

public class Downloader extends TimerTask {
    public void run() {
        doStuff();
    }
}

... elsewhere ...

Timer myTimer = new Timer();

public void gogogo() {
    myTimer.scheduleAtFixedRate(new Downloader(), 0, 500);
}

That's a little different in that your task will be scheduled to run every 500 ms rather than with a 500 ms delay. When you're done, just use myTimer.cancel() to stop the repeating task execution.

eaolson