当池大小为 1 时,ScheduledExecutorService 是否保证顺序?
Does ScheduledExecutorService guarantee order when pool size is one?
我有一个 ScheduledExecutorService
,其池大小为 1
个线程。
如果我使用该服务安排许多具有相同延迟的任务,在执行期间是否保留安排顺序?
是的,订单被保留。来自 javadocs
Delayed tasks execute no sooner than they are enabled, but without any real-time guarantees about when, after they are enabled, they will commence. Tasks scheduled for exactly the same execution time are enabled in first-in-first-out (FIFO) order of submission.
你也可以在实际中看到这个
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
可以,只要使用的调度器实现遵循接口规范即可。例如,new ScheduledThreadPoolExecutor(1)
将使用 DelayedWorkQueue
来保留顺序。
根据 javadoc 所有 ScheduledExecutorService
实施应保留顺序:
Tasks scheduled for exactly the same execution time are enabled in first-in-first-out (FIFO) order of submission.
可以用下面的例子来测试实现:
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);
}
}
我有一个 ScheduledExecutorService
,其池大小为 1
个线程。
如果我使用该服务安排许多具有相同延迟的任务,在执行期间是否保留安排顺序?
是的,订单被保留。来自 javadocs
Delayed tasks execute no sooner than they are enabled, but without any real-time guarantees about when, after they are enabled, they will commence. Tasks scheduled for exactly the same execution time are enabled in first-in-first-out (FIFO) order of submission.
你也可以在实际中看到这个
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
可以,只要使用的调度器实现遵循接口规范即可。例如,new ScheduledThreadPoolExecutor(1)
将使用 DelayedWorkQueue
来保留顺序。
根据 javadoc 所有 ScheduledExecutorService
实施应保留顺序:
Tasks scheduled for exactly the same execution time are enabled in first-in-first-out (FIFO) order of submission.
可以用下面的例子来测试实现:
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);
}
}