【问题标题】:Does ScheduledExecutorService guarantee order when pool size is one?当池大小为 1 时,ScheduledExecutorService 是否保证顺序?
【发布时间】:2021-07-13 15:43:36
【问题描述】:

我有一个ScheduledExecutorService,其池大小为1 个线程。

如果我使用该服务以相同的延迟调度许多任务,在执行期间是否保留了调度顺序?

【问题讨论】:

    标签: java concurrency java.util.concurrent


    【解决方案1】:

    可以,只要使用的调度程序实现遵循接口规范。例如,new ScheduledThreadPoolExecutor(1) 将使用 DelayedWorkQueue 来保留订单。

    根据javadoc,所有ScheduledExecutorService 实现都应保持顺序:

    按照先进先出 (FIFO) 提交顺序启用安排在完全相同执行时间的任务。

    可以通过以下示例测试实现:

    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);
        }
    }
    

    【讨论】:

      【解决方案2】:

      是的,订单被保留。来自 javadocs

      延迟任务在启用后立即执行,但无法实时保证启用后何时开始执行。按照先进先出 (FIFO) 的提交顺序启用计划在完全相同的执行时间的任务。

      你也可以看到这一点

          public static void main(String args[]) {
              ScheduledExecutorService e = Executors.newScheduledThreadPool(1);
              
              e.schedule(delay("delay for 1 second", 10), 1, TimeUnit.SECONDS);
              e.schedule(delay("delay for 5 second", 0), 5, TimeUnit.SECONDS);
              e.schedule(delay("delay for 3 second", 0), 3, TimeUnit.SECONDS);
              e.schedule(delay("delay for 7 second", 0), 7, TimeUnit.SECONDS);
              e.schedule(delay("delay for 2 second", 0), 2, TimeUnit.SECONDS);
          }
          
          private static Runnable delay(String message, int initialDelay) {
              return () -> {
                  Thread.sleep(initialDelay);
                  System.out.println(message);
              };
          }
      

      打印

      delay for 1 second
      delay for 2 second
      delay for 3 second
      delay for 5 second
      delay for 7 second
      

      【讨论】:

        猜你喜欢
        • 2013-05-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-12
        • 2020-01-27
        • 2021-05-03
        • 2021-10-04
        • 2014-07-22
        相关资源
        最近更新 更多