Turning Asynchronous Calls into Synchronous Responses with CompletableFuture in Java
This article demonstrates how to convert multiple asynchronous queries into a synchronous response using Java's CompletableFuture, providing step‑by‑step code examples in both Java and Groovy, explaining execution flow, timeout handling, and practical considerations for WebSocket‑like scenarios.
Background
Earlier we used java.util.concurrent.CountDownLatch to turn multiple asynchronous queries into a synchronous response by creating a latch per task, waiting for all tasks, then assembling the result.
Using CompletableFuture
java.util.concurrent.CompletableFutureprovides a more flexible way to compose asynchronous operations, especially when a request must wait for another async task before producing a response (e.g., a WebSocket message exchange).
Java example
The program below creates a CompletableFuture, completes it in a separate thread after a delay, and retrieves the result with a timeout.
import com.funtester.frame.SourceCode;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class PerFunTest extends SourceCode {
private static final Logger log = LogManager.getLogger(PerFunTest.class);
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
log.info("Test start");
CompletableFuture<String> future = new CompletableFuture<>();
// Run async task in a new thread
new Thread(() -> {
// Simulate work
try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
future.complete("FunTester");
log.info("Value assigned");
}).start();
// Wait up to 5 seconds for the result
String result = future.get(5, TimeUnit.SECONDS);
if (result != null) {
log.info("Retrieved value: {}", result);
}
}
}Console output shows the start log, the value retrieval, and the completion log occurring almost simultaneously, confirming that the asynchronous task finished before the timeout. If the simulated delay exceeds the timeout, future.get(...) throws a TimeoutException, which must be handled to avoid blocking the request indefinitely.
Groovy example
The same logic expressed in Groovy demonstrates language‑agnostic usage on the JVM.
import com.funtester.frame.SourceCode
import groovy.util.logging.Log4j2
import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit
@Log4j2
class Ts extends SourceCode {
static void main(String[] args) {
log.info("Test start")
def future = new CompletableFuture<String>()
// Asynchronous block
Thread.start {
try { Thread.sleep(1000) } catch (InterruptedException ignored) {}
future.complete("FunTester")
log.info("Value assigned")
}
String result = future.get(5, TimeUnit.SECONDS)
if (result != null) {
log.info("Retrieved value: $result")
}
}
}Key points and caveats
Use future.complete(value) to signal successful completion; alternatively future.completeExceptionally(e) can propagate errors.
The timeout passed to future.get(timeout, unit) should be chosen based on expected async latency and overall request latency requirements.
When the timeout expires, a TimeoutException is thrown; callers should catch it and decide whether to return a fallback response or retry. CompletableFuture can be chained with methods such as thenApply, thenCompose, and whenComplete for more complex async workflows.
Further reading
Explore other classes in java.util.concurrent (e.g., ExecutorService, ScheduledThreadPoolExecutor) to build robust asynchronous pipelines.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
