Java scheduleAtFixedRate + Thread.sleep

Dmitry_Bl :

I'm just exploring method scheduleAtFixedRate of class ScheduledExecutorService in Java.

Here is my suspicious code:


ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

  Runnable command = () -> {
    System.out.println("Yo");
    try {
      Thread.sleep(4000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  };

  scheduledExecutorService.scheduleAtFixedRate(command, 0, 1, TimeUnit.SECONDS);

I expected that every 1 second scheduledExecutorService will try to take new thread from the pool and start it.

API says: "scheduledExecutorService creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period. /(unimportant deleted)/ If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute."

Result - every new thread starts every 4 seconds.

So, the questions:

  1. What's the catch - Does Thread.sleep() stop all threads or nuance in this behavior - "If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute"?

  2. If "will not concurrently execute" is true in this situation - why do we need this pool of several threads if every thread will start after execution of previous thread?

  3. Is there any simple valid example of usage of scheduleAtFixedRate, where one thread starts while previous still executes?

Egor Zaitsev :
  1. The answer is in the quote you provided. Executor waits until the task finishes before launching this task again. It prevents concurrent execution of many instances of one task - in most cases this behaviour is needed. In your case Executor starts a task, then waits 1 second of delay, then waits 3 more seconds until current task is done and only then starts this task again (It does not necessarily start new thread, it may start the task in the same thread).

  2. Your code does not use thread pool at all - you can get exactly same result using single thread executor.

  3. If you want to get this behaviour:

    I expected that every 1 second scheduledExecutorService will try to take new thread from the pool and start it.

    Then you may write is like this:

    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
    
    Runnable command = () -> {
        System.out.println("Yo");
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    };
    
    Runnable commandRunner = () -> {
        scheduledExecutorService.schedule(command, 0, TimeUnit.SECONDS);
    }
    
    scheduledExecutorService.scheduleAtFixedRate(commandRunner, 0, 1, TimeUnit.SECONDS);
    

    (It's better to create a single-threaded ScheduledExecutorService that runs commandRunner and create a thread pool based ExecutorService that is used by commandRunner to execute command)

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=417188&siteId=1