-
Bug
-
Resolution: Fixed
-
P3
-
8
-
None
It appears to be the intent that Futures for all thread pool tasks are complete after awaitTermination returns. But for periodic tasks that are actively executing when shutdown is called asynchronously, they are not cancelled and Future.get never returns.
import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.concurrent.*;
public class STPEShutdown {
public static void main(String[] args) throws Throwable {
final int n = 4;
final Future<?>[] futures = new Future<?>[n];
final ScheduledThreadPoolExecutor pool
= new ScheduledThreadPoolExecutor(n/2);
final CountDownLatch running = new CountDownLatch(n/2);
final CountDownLatch proceed = new CountDownLatch(1);
final Runnable task = () -> {
try {
running.countDown();
proceed.await();
} catch (InterruptedException t) { throw new Error(t); }
};
for (int i = 0; i < n; i++)
futures[i] = pool.scheduleWithFixedDelay(task, 0, 1, SECONDS);
running.await();
pool.shutdown();
proceed.countDown();
if (!pool.awaitTermination(10, SECONDS))
throw new Error("timed out");
for (Future<?> future : futures) {
System.err.printf("isDone=%s isCancelled=%s%n",
future.isDone(),
future.isCancelled());
}
}
}
prints:
isDone=false isCancelled=false
isDone=false isCancelled=false
isDone=true isCancelled=true
isDone=true isCancelled=true
The spec is not entirely clear on what should happen. It seems that the spec and the implementation should be improved to match the apparent common sense intent. As far as possible, it should be guaranteed that futures are complete on executor termination, that cancellation of the future inhibits subsequent execution of the task, and that abnormal termination of a periodic task not only inhibits subsequent executions but is also reflected in the Future's result.
import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.concurrent.*;
public class STPEShutdown {
public static void main(String[] args) throws Throwable {
final int n = 4;
final Future<?>[] futures = new Future<?>[n];
final ScheduledThreadPoolExecutor pool
= new ScheduledThreadPoolExecutor(n/2);
final CountDownLatch running = new CountDownLatch(n/2);
final CountDownLatch proceed = new CountDownLatch(1);
final Runnable task = () -> {
try {
running.countDown();
proceed.await();
} catch (InterruptedException t) { throw new Error(t); }
};
for (int i = 0; i < n; i++)
futures[i] = pool.scheduleWithFixedDelay(task, 0, 1, SECONDS);
running.await();
pool.shutdown();
proceed.countDown();
if (!pool.awaitTermination(10, SECONDS))
throw new Error("timed out");
for (Future<?> future : futures) {
System.err.printf("isDone=%s isCancelled=%s%n",
future.isDone(),
future.isCancelled());
}
}
}
prints:
isDone=false isCancelled=false
isDone=false isCancelled=false
isDone=true isCancelled=true
isDone=true isCancelled=true
The spec is not entirely clear on what should happen. It seems that the spec and the implementation should be improved to match the apparent common sense intent. As far as possible, it should be guaranteed that futures are complete on executor termination, that cancellation of the future inhibits subsequent execution of the task, and that abnormal termination of a periodic task not only inhibits subsequent executions but is also reflected in the Future's result.