Suppose we run execution with CompletableFuture.runAsync(..) and in runnable we have try-with-resources block (we are using some resource that should be closed whatever happens), and at some point when execution is not finished in try block we cancel the completable future... altough execution is stopped the resource that should be closed is not closed the close() of AutoClosable is not called...
Is that a java issue or there is a way to do that properly? without hacky workarounds like using futures (that support interruption etc..), and if its expected behaviour how should one handle similar situation when non interruptable CompletableFuture is canceled...?
public class AutoClosableResourceTest {
public static class SomeService{
public void connect(){
System.out.println("connect");
}
public Integer disconnect(){
System.out.println("disconnect");
return null;
}
}
public static class AutoClosableResource<T> implements AutoCloseable {
private final T resource;
private final Runnable closeFunction;
private AutoClosableResource(T resource, Runnable closeFunction){
this.resource = resource;
this.closeFunction = closeFunction;
}
public T get(){
return resource;
}
@Override
public void close() throws Exception {
closeFunction.run();
}
}
@Test
public void testTryWithResource() throws InterruptedException {
SomeService service = new SomeService();
CompletableFuture<Void> async = CompletableFuture.runAsync(() -> {
try (AutoClosableResource<SomeService> resource = new AutoClosableResource<>(service, service::disconnect)) {
resource.get().connect();
while (true) {
Thread.sleep(1000);
System.out.println("working...");
}
} catch (Exception e) {
e.printStackTrace();
}
});
Thread.sleep(2500);
async.cancel(true);
Thread.sleep(2500);
}
}
this will produce
connect
working...
working...
working...
working...
as you can see it does not call cancel() and leaves resource opened...
It seems you have difficulties in understanding what the purpose of CompletableFuture
is. Have a look at the first sentence of its class documentation:
A
Future
that may be explicitly completed (setting its value and status), …
So unlike FutureTask
which is completed by the thread executing its run
method, a CompletableFuture
can be completed by any thread which will set its value/status at an arbitrary point of time. The CompletableFuture
doesn’t know which thread will complete it and it doesn’t even know whether there is a thread currently working on its completion.
Therefore the CompletableFuture
can not interrupt the right thread when being canceled. That’s a fundamental part of its design.
If you want a worker thread that you can interrupt you are better off using FutureTask
/ThreadPoolExecutor
. The task scheduled that way may still complete a CompletableFuture
at its end.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With