问题描述
我有一个 scheduledexecutorservice
,其池大小为 1
个线程。
如果我使用该服务以相同的延迟调度多个任务,在执行期间是否保留调度顺序?
解决方法
是的,订单被保留。来自 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",3,TimeUnit.SECONDS);
e.schedule(delay("delay for 7 second",7,TimeUnit.SECONDS);
e.schedule(delay("delay for 2 second",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
,
是的,只要使用的调度器实现将遵循接口规范。例如,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);
}
}