As @Slaw already suspected in the question comments while I composed this answer, its fundamentally a sequencing problem, hidden by a bit of compiler syntactic sugar.
JLS 14.20.3.2 states that this:
/* task creation if option 1 */
try (/* option 1 or 2 resource statement here */) {
var taskFuture = taskExecutor.submit(() -> {
task.run();
return true;
});
var result = taskFuture.get(30_000, TimeUnit.MILLISECONDS);
System.out.println("Got result: " + result);
} catch (Exception e) {
System.out.println("Caught exception: " + e);
throw new RuntimeException(e);
} /* finally if option 1 */
is fundamentally treated as this:
/* task creation if option 1 */
try{
try (/* option 1 or 2 resource statement here */){
var taskFuture = taskExecutor.submit(() -> {
task.run();
return true;
});
var result = taskFuture.get(30_000, TimeUnit.MILLISECONDS);
System.out.println("Got result: " + result);
}
} catch (Exception e) {
System.out.println("Caught exception: " + e);
throw new RuntimeException(e);
} /* finally if option 1 */
Which already hints at the problem.
taskExecutor.close()
will happen (as part of exiting the inner try) before your own finally ever executes, leading to taskExecutor shutdown hanging forever* because the AtomicBoolean
value is not yet true.AtomicBoolean
to true
) before the call to taskExecutor.close()
, which means that method returns as soon as the task has (quite soon, if not already) terminated.