通过阻止方法调用创建CompletableFuture

时间:2019-06-07 11:27:05

标签: java multithreading concurrency completable-future

如何将阻塞方法调用“转换”为CompletableFuture?示例:

T waitForResult() throws InterruptedException {
    obj.await(); // blocking call
    // ...
    return something;
}

我需要把它变成这样:

CompletableFuture.of(this::waitForResult); // .of(Callable<T>) doesn't exist

要考虑的一些事情:

  1. waitForResult()可能会引发异常。必须正确处理这些内容,以便completableFuture.get()会抛出InterruptedExceptionExecutionException
  2. 不得涉及其他线程(supplyAsync()会这样做)。
  3. 它必须是CompletableFuture(可能是包装好的)。

我尝试过此操作,但这无法正确处理异常:

CompletableFuture.completedFuture(Void.TYPE).thenApply(v -> {
    try {
        listener.await();
        // ...
        return listener.getResult();
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    } catch (SnmpException e) {
        throw new RuntimeException(e);
    }
});

我认识Create CompletableFuture from a sync method call,但这对我没有帮助:

  • 问题中的原始代码阻塞了主线程
  • 答案中的代码要么包含第三个线程,要么未正确处理异常(如果我错了,请纠正我)

3 个答案:

答案 0 :(得分:1)

您可以尝试这样做,因为它严重滥用了CompletableFuture,但您必须确定其是否适合您的用例:

private static <T> CompletableFuture<T> supplySynchronously(Callable<T> callable) {
    CompletableFuture<T> f = new CompletableFuture() {

        public T get() throws InterruptedException, ExecutionException {
            synchronized (callable) {
                if (!isDone()) {
                    try {
                        T result = callable.call();
                        complete(result);
                    } catch (Exception e) {
                        completeExceptionally(e);
                    }

                }
            }
            return (T) super.get();
        }
    };
    return f;
}

答案 1 :(得分:1)

让方法Listener.await()调用方法CountDownLatch.await()

class Listener {
   CountDownLatch latch = new CountDownLatch(counter);

   void someMethod(){
     latch.countdown();
   }

   public void await() {
      latch.await();
   }
}

然后您可以通过以下方式将其转换为异步方式:

class Listener {
   AsynCountDownLatch latch = new AsynCountDownLatch(counter);

   void someMethod(){ // here nothing changed
     latch.countdown();
   }

   public CompletableFuture<Void> async() {
      return latch.fin;
   }
}

class AsynCountDownLatch extends AsynCountDownLatch {
   CompletableFuture<Void> fin = new CompletableFuture<>();

   public AsynCountDownLatch(long counter) {
     super(counter);
   }

   public void countdown() {
       super.countdown();
       if (super.getCount()==0L) {
           fin.complete(null);
       }
   }
 }

UPDT:如果侦听器使用另一个类,则也必须修改/扩展/替换该​​类,以将阻塞操作转换为非阻塞操作。没有通用的方法可以进行这种转换。

答案 2 :(得分:0)

我不确定我是否理解您的要求。这满足他们吗?

private <T> CompletableFuture<T> supplySynchronously(Callable<T> callable) {
    CompletableFuture<T> f = new CompletableFuture<>();
    try {
        f.complete(callable.call());
    } catch (Exception e) {
        f.completeExceptionally(e);
    }
    return f;
}