如何在取消的CompletableFuture中释放资源

vac*_*ach 4 java concurrency java-8 try-with-resources

Uscase

假设我们使用CompletableFuture.runAsync(..)运行执行,并且在runnable中我们有try-with-resources块(我们正在使用一些应该在发生任何事情时关闭的资源),并且在某些时候在try块我们没有完成执行时取消可完成的未来...尽管执行停止,应关闭的资源未关闭,AutoClosable的close()未被调用...


这是一个java问题还是有办法正确地做到这一点?没有hacky变通办法,如使用期货(支持中断等),如果它的预期行为如何处理类似的情况,当不可中断的CompletableFuture被取消...?


代码

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);

    }
}
Run Code Online (Sandbox Code Playgroud)

这将产生

connect
working...
working...
working...
working...
Run Code Online (Sandbox Code Playgroud)

你可以看到它没有调用cancel()并打开资源...

Hol*_*ger 5

你似乎很难理解其目的CompletableFuture是什么.看看它的类文档的第一句话:

一个Future可以明确完成(设置它的价值和地位),...

因此,与FutureTask执行其run方法的线程完成的不同,a CompletableFuture可以由任何线程完成,该线程将在任意时间点设置其值/状态.在CompletableFuture不知道哪个线程将完成它,它甚至不知道是否有目前正在其完成一个线程.

因此,CompletableFuture取消时不能中断正确的线程.这是其设计的基本部分.

如果你想要一个你可以打断的工作线程,最好使用FutureTask/ ThreadPoolExecutor.以这种方式安排的任务可能仍然CompletableFuture在其结束时完成.