Reputation: 16938
How can I "convert" a blocking method call to a CompletableFuture? Example:
T waitForResult() throws InterruptedException {
obj.await(); // blocking call
// ...
return something;
}
I need to turn that into this:
CompletableFuture.of(this::waitForResult); // .of(Callable<T>) doesn't exist
Some things to consider:
waitForResult()
may throw exceptions. These have to be handled correctly, so that completableFuture.get()
would throw an InterruptedException
or an ExecutionException
.supplyAsync()
would do so).I tried this, but this won't handle exceptions correctly:
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);
}
});
I know Create CompletableFuture from a sync method call, but it doesn't help me:
Upvotes: 2
Views: 1996
Reputation: 13515
Let the method Listener.await()
invokes method CountDownLatch.await()
:
class Listener {
CountDownLatch latch = new CountDownLatch(counter);
void someMethod(){
latch.countdown();
}
public void await() {
latch.await();
}
}
then you can convert it to an asynchronous in following way:
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: if the listener uses another class, then that class also has to be modified/extended/replaced to convert blocking operations to non-blocking. There is no universal way to do such a conversion.
Upvotes: 1
Reputation: 1454
You can try this, its an big abuse of CompletableFuture but you have to decide if its acceptable for your use case:
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;
}
Upvotes: 1
Reputation: 8983
I'm not sure I understand your requirements. Does this meet them?
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;
}
Upvotes: 1