简体   繁体   中英

How can I replace Thread.sleep() in an infinite loop?

I have an infinite loop inside my main, it runs a job which is also an infinite loop, and wait for it to throw an error. Then it sleeps for a given amount of time and starts the task again.

public static void main(String[] args) {
    while (true) {
        try {
            MyClass myClass = new MyClass();
            myClass.startInfiniteLoop();
        }
        catch (SomeException ex) {
            try {
                Thread.sleep(MyClass.DEFAULT_SLEEP_TIME);
            }
            catch (InterruptedException ex2) {
                System.exit(-1);
            }
        }
    }
}

This works fine, but I wonder if this could be done better, perhaps with an ExecutorService as I (and my IDE) don't like Thread.sleep() in a while (true) loop.

I have read a lot of questions and their answers about ScheduledExecutorService and task management, but I did not find this particular case since it's not really a schedule, I don't know if and when the task if going to end.

You can use a ScheduledExecutorService :

ScheduledExecutorService s=Executors.newScheduledThreadPool(1);
s.scheduleWithFixedDelay(new Runnable() {
  public void run() {
    try {
      MyClass myClass = new MyClass();
      myClass.startInfiniteLoop();
    } catch(SomeException ex) {}
  }
}, 0, MyClass.DEFAULT_SLEEP_TIME, TimeUnit.MILLISECONDS);

The key point is to use scheduleWithFixedDelay rather than scheduleAtFixedRate to ensure the specified time elapses between the subsequent executions just like with your sleep approach. However, note that even with “fixed rate” the new execution will not start when the old one has not finished yet. It's documentation says: “ If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.

Further note that you still have to catch the exception like in my code example as otherwise the executor will cancel the scheduled task once it threw an uncatched exception.

If you can take the MyClass and rework it to have a Runnable that does what only one loop iteration of the MyClass would have done, then you can use a scheduling executor service, telling the service to run the Runnable once every time period.

--- Updated by request of a quick example ---

The following is not strictly correct Java code, it is pesudo-java.

 public class MyRepeatingTask implements Runnable {

    private final ScheduledThreadpoolExecutor executor;

    public MyRepeatingTask(ScheduledThreadpoolExecutor executor) {
      this.executor = executor;
    }

    public void run() {
      try {
        doMyVariableLengthThing();
        // alternatively, you could also schedule a new instance
        executor.schedule(this, 1, TimeUnit.SECONDS);
      } catch (Exception e) {
        cleanup();
      }
    }
 }

and then to start the ball rolling

 ScheduledThreadpoolExecutor executor = new ScheduledThreadpoolExecutor(1);

 executor.execute(new MyRepeatingTask(executor));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM