Search code examples
javaconcurrencyjava.util.concurrent

Does ScheduledExecutorService guarantee order when pool size is one?


I have a ScheduledExecutorService that has a pool size of 1 threads.

If I schedule many tasks using that service with the same delay, is the order of scheduling preserved during the execution?


Solution

  • Yes, as long as the scheduler implementation used will follow the interface specification. For example, new ScheduledThreadPoolExecutor(1) will use a DelayedWorkQueue which will preserve the order.

    As per javadoc all ScheduledExecutorService implementations should preserve order:

    Tasks scheduled for exactly the same execution time are enabled in first-in-first-out (FIFO) order of submission.

    One can test the implementation with the example below:

    import com.google.code.tempusfugit.concurrency.IntermittentTestRunner;
    import com.google.code.tempusfugit.concurrency.annotations.Intermittent;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    
    import java.util.concurrent.*;
    import java.util.concurrent.atomic.AtomicInteger;
    
    import static org.assertj.core.api.Assertions.assertThat;
    
    
    @RunWith(IntermittentTestRunner.class)
    public class ScheduledExecutorServiceTest {
        @Test
        @Intermittent(repetition = 20)
        public void preservesOrderOfTasksScheduledWithSameDelay() throws InterruptedException {
            ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);
    
            AtomicInteger atomicInteger = new AtomicInteger(0);
            int numTasks = 1_000;
            CountDownLatch countDownLatch = new CountDownLatch(numTasks);
            for (int i = 0; i < numTasks; i++) {
                int finalI = i;
                scheduledExecutorService.schedule(() -> {
                    atomicInteger.compareAndSet(finalI, finalI + 1);
                    countDownLatch.countDown();
                }, 10, TimeUnit.MILLISECONDS);
            }
            countDownLatch.await();
    
            assertThat(atomicInteger.get()).isEqualTo(numTasks);
        }
    }