I have the following code in Java (I use Oracle Java 17):
package com.test;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class Solution {
public void startCompletableFutureExample() {
CompletableFuture.runAsync(() -> {
System.out.println("async operation");
})
.completeOnTimeout(
timeout(), 10000, TimeUnit.MILLISECONDS);
}
private Void timeout() {
System.out.println("timeout happens");
return null;
}
}
when I call the startCompletableFutureExample()
method I have the following output:
timeout happens
async operation
while I'd expect to get the only one as timeout has not been even close:
async operation
Why do I have method completeOnTimeout
to be run before runAsync
? Am I doing something wrong?
Answering my own question - if it is necessary to run asynchronously CompletableFuture or cancel it by timeout expiration, as Slaw suggested it is better to use handle
method. I've got the desired behavior with the following code:
package com.test;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class Solution {
public void startCompletableFutureExample() {
CompletableFuture<String> f = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "async operation";
}).orTimeout(10, TimeUnit.MILLISECONDS);
f.handleAsync((msg, ex) -> {
if (ex instanceof TimeoutException) {
System.out.println("timeout happens");
f.cancel(true);
} else {
System.out.println(msg);
}
return null;
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Now if I run it, I'll get a timeout reached first and thus the output would be only:
timeout happens
However if I set Thread.sleep(5)
instead of Tread.sleep(50)
, I will get only:
async operation
which is an expected value.