Я не согласен с гипотезой, что вы должны получать только 10 прерываний.
Assume the CPU has 1 core.
1. Main thread starts Watcher and sleeps
2. Watcher starts and adds 100 Waiters then blocks
3. Waiter 1-10 start and sleep in sequence
4. Main wakes and interrupts Watcher then sleeps
5. Watcher cancels Waiter 1-5 then is yielded by the OS (now we have 5 interrupts)
6. Waiter 11-13 start and sleep
7. Watcher cancels Waiter 6-20 then is yielded by the OS (now we have 13 interrupts)
8. Waiter 14-20 are "started" resulting in a no-op
9. Waiter 21-24 start and sleep
....
По сути, я утверждаю, что нет никакой гарантии, что потоку Watcher будет разрешено отменить все 100 экземпляров RunnableFuture "Waiter", прежде чем он должен будет выдавать временной интервал и позволить рабочим потокам ExecutorService запускать больше задач Waiter.
Обновление: Отображение кода от AbstractExecutorService
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks) {
RunnableFuture<T> f = newTaskFor(t);
futures.add(f);
execute(f);
}
for (Future<T> f : futures) {
if (!f.isDone()) {
try {
f.get(); //If interrupted, this is where the InterruptedException will be thrown from
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done = true;
return futures;
} finally {
if (!done)
for (Future<T> f : futures)
f.cancel(true); //Specifying "true" is what allows an interrupt to be sent to the ExecutorService's worker threads
}
}
Блок finally, который содержит f.cancel(true)
, - это когда прерывание распространяется на задачу, которая в данный момент выполняется. Как вы можете видеть, это узкий цикл, но нет никакой гарантии, что поток, выполняющий цикл, сможет перебирать все экземпляры Future
в одном временном интервале.