Sami
Sami

Reputation: 7837

how can i make a thread sleep for a while and then start working again?

I have the following code:

public void run() 
{
     try 
     {
         logger.info("Looking for new tasks to fetch...  ");
         // definitions ..

         for(Task t: tasks)
         {
             logger.info(" Task " + t.getId() + " is being fetched ");
            // processing ... fetching task info from db using some methods
         }
         Thread.sleep(FREQUENCY);
         //t.start();
     } catch (Exception e) 
     {
         logger.info("FetcherThread interrupted: "+e.getMessage());
     }
}

I'm trying to make the thread to sleep for a specific time "FREQUENCY" and then work again. when I execute this code in eclipse, the thread works only once and then nothing happens and process terminates. If I remove the comment from the statement: t.start(), I get "FetcherThread interrupted: null". Can anyone tell me where I'm going wrong?

N.B.: I want the thread to be working all the time, but fetching on periods (say every 5 minutes)

Upvotes: 2

Views: 7999

Answers (9)

Andrzej Doyle
Andrzej Doyle

Reputation: 103847

You're missing any sort of loop in that code.

It seems that the thread is actually doing what you tell it to do: it runs all the tasks, then sleeps for a bit - then it has no more work to do, and so exits. There are several ways to address this, in ascending order of complexity and correctness:

  1. The simple (and naive) way to address this is to wrap the try-catch block in an infinite loop (while(true) { ... }). This way after the thread finishes sleeping, it will loop back to the top and process all the tasks again.

  2. However this isn't ideal, as it's basically impossible to stop the thread. A better approach is to declare a boolean field (e.g. boolean running = true;), and change the loop to while(running). This way, you have a way to make the thread terminate (e.g. expose a method that sets running to false.) See Sun's Why is Thread.stop() deprecated article for a longer explanation of this.

  3. And taking a step further back, you may be trying to do this at too low a level. Sleeping and scheduling isn't really part of the job of your Runnable. The actual solution I would adopt is to strip out the sleeping, so that you have a Runnable implementation that processes all the tasks and then terminates. Then I would create a ScheduledExecutorService, and submit the "vanilla" runnable to the executor - this way it's the job of the executor to run the task periodically.

The last solution is ideal from an engineering perspective. You have a class that simply runs the job once and exits - this can be used in other contexts whenever you want to run the job, and composes very well. You have an executor service whose job is the scheduling of arbitrary tasks - again, you can pass different types of Runnable or Callable to this in future, and it will do the scheduling bit just as well. And possibly the best part of all, is that you don't have to write any of the scheduling stuff yourself, but can use a class in the standard library which specifically does this all for you (and hence is likely to have the majority of bugs already ironed out, unlike home-grown concurrency code).

Upvotes: 7

Alex Stybaev
Alex Stybaev

Reputation: 4693

You could try ScheduledExecutorService (Javadoc). And us it's scheduleAtFixedRate, which:

Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.

Upvotes: 0

Scorpion
Scorpion

Reputation: 3986

You need to put the sleep in an infinite loop (or withing some condition specifying uptill when you want to sleep). As of now the sleep method is invoked at the end of the run method and behavior you observe is correct. The following demo code will print "Sleep" on the console after sleeping for a second. Hope it helps.

import java.util.concurrent.TimeUnit;

public class Test implements Runnable {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Test t = new Test();
        Thread thread = new Thread(t);
        thread.start();
    }

    public void run() {
        try {
            // logger.info("Looking for new tasks to fetch...  ");
            // definitions ..

            // for(Task t: tasks)
            // {
            // logger.info(" Task " + t.getId() + " is being fetched ");
            // // processing ... fetching task info from db using some methods
            // }
            while (true) { // your condition here
                TimeUnit.SECONDS.sleep(1);
                System.out.println("Sleep");
            }

            // t.start();
        } catch (Exception e) {
            // logger.info("FetcherThread interrupted: "+e.getMessage());
        }
    }
}

Upvotes: 0

Marko Topolnik
Marko Topolnik

Reputation: 200296

Task scheduling has first-class support in Java, don't reinvent it. In fact, there are two implementations: Timer (old-school) and ScheduledExecutorService (new). Read up on them and design your app aroud them.

Upvotes: 1

giorashc
giorashc

Reputation: 13713

public void run() 
{
    while (keepRunning) {
        try 
        {
            logger.info("Looking for new tasks to fetch...  ");
            // definitions ..

            for(Task t: tasks)
            {
                logger.info(" Task " + t.getId() + " is being fetched ");
                // processing ... fetching task info from db using some methods
                t.start();
            }
            Thread.sleep(FREQUENCY);

        } catch (Exception e) {
            keepRunning = false;
            logger.info("FetcherThread interrupted: "+e.getMessage());
        }  
    }
}

Add a member call keepRunning to your main thread and implement an accessor method for setting it to false (from wherever you need to stop the thread from executing the tasks)

Upvotes: 0

jontro
jontro

Reputation: 10636

Put the thread in a loop as others have mentioned here.

I would like to add that calling Thread.start more than once is illegal and that is why you get an exception.

If you would like to spawn multiple thread create one Thread object per thread you want to start.

See http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#start()

Upvotes: 0

Subir Kumar Sao
Subir Kumar Sao

Reputation: 8411

You can put the code inside a loop.( May be while)

while(condition) // you can make it while(true) if you want it to run infinitely.
{
      for(Task t: tasks)
     {
         logger.info(" Task " + t.getId() + " is being fetched ");
        // processing ... fetching task info from db using some methods
     }
     Thread.sleep(FREQUENCY);
}

Whats happening in your case its running the Task loop then sleeping for some time and exiting the thread.

Upvotes: 0

Bananeweizen
Bananeweizen

Reputation: 22080

You need some kind of loop to repeat your workflow. How shall the control flow get back to the fetching part?

Upvotes: 0

Luka Ramishvili
Luka Ramishvili

Reputation: 899

Try executing the task on a different thread.

Upvotes: 0

Related Questions