FULL PRODUCT VERSION :
A DESCRIPTION OF THE PROBLEM :
ExecutorService::invokeAll may block indefinitely, if shutdownNow was called and not all tasks have been started.
InvokeAll calls get for all FutureTasks, which are not done. After calling shutdownNow this will block forever as the FutureTask will never be executed. Obviously pending tasks are not interrupted.
From AbstractExecutorService:
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
ArrayList<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 (int i = 0, size = futures.size(); i < size; i++) {
Future<T> f = futures.get(i);
if (!f.isDone()) {
try {
f.get(); <--------------------------------------- Blocks here
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
In the testcase below the message "invokeAll returned" should be printed
ACTUAL -
The message "invokeAll returned" is not printed. executorInvokerThread hangs.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public class ThreadTest {
@Test
public void executorServiceTest() {
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Callable<Void>> tasks = new ArrayList<>();
tasks.add((( Callable<Void>) () -> { System.out.println("callable 1"); Thread.sleep(500); return null; }) );
tasks.add((( Callable<Void>) () -> { System.out.println("callable 2"); Thread.sleep(500); return null; }) );
tasks.add((( Callable<Void>) () -> { System.out.println("callable 3"); Thread.sleep(500); return null; }) );
tasks.add((( Callable<Void>) () -> { System.out.println("callable 4"); Thread.sleep(500); return null; }) );
tasks.add((( Callable<Void>) () -> { System.out.println("callable 5"); Thread.sleep(500); return null; }) );
tasks.add((( Callable<Void>) () -> { System.out.println("callable 6"); Thread.sleep(500); return null; }) );
Thread executorInvokerThread = new Thread( () -> {
try {
executor.invokeAll(tasks);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("invokeAll returned");
});
executorInvokerThread.start();
try {
Thread.sleep(800);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("ShutdownNow");
executor.shutdownNow();
try {
executor.awaitTermination(2, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Shutdown complete");
try {
executorInvokerThread.join(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
---------- END SOURCE ----------
A DESCRIPTION OF THE PROBLEM :
ExecutorService::invokeAll may block indefinitely, if shutdownNow was called and not all tasks have been started.
InvokeAll calls get for all FutureTasks, which are not done. After calling shutdownNow this will block forever as the FutureTask will never be executed. Obviously pending tasks are not interrupted.
From AbstractExecutorService:
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
ArrayList<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 (int i = 0, size = futures.size(); i < size; i++) {
Future<T> f = futures.get(i);
if (!f.isDone()) {
try {
f.get(); <--------------------------------------- Blocks here
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
In the testcase below the message "invokeAll returned" should be printed
ACTUAL -
The message "invokeAll returned" is not printed. executorInvokerThread hangs.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public class ThreadTest {
@Test
public void executorServiceTest() {
ExecutorService executor = Executors.newFixedThreadPool(2);
List<Callable<Void>> tasks = new ArrayList<>();
tasks.add((( Callable<Void>) () -> { System.out.println("callable 1"); Thread.sleep(500); return null; }) );
tasks.add((( Callable<Void>) () -> { System.out.println("callable 2"); Thread.sleep(500); return null; }) );
tasks.add((( Callable<Void>) () -> { System.out.println("callable 3"); Thread.sleep(500); return null; }) );
tasks.add((( Callable<Void>) () -> { System.out.println("callable 4"); Thread.sleep(500); return null; }) );
tasks.add((( Callable<Void>) () -> { System.out.println("callable 5"); Thread.sleep(500); return null; }) );
tasks.add((( Callable<Void>) () -> { System.out.println("callable 6"); Thread.sleep(500); return null; }) );
Thread executorInvokerThread = new Thread( () -> {
try {
executor.invokeAll(tasks);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("invokeAll returned");
});
executorInvokerThread.start();
try {
Thread.sleep(800);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("ShutdownNow");
executor.shutdownNow();
try {
executor.awaitTermination(2, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Shutdown complete");
try {
executorInvokerThread.join(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
---------- END SOURCE ----------
- relates to
-
JDK-8286463 DiscardPolicy may block invokeAll forever
-
- Open
-