What's the difference between a Future and a Promise?
A Future is essentially a container, holding the result of a computation that might yet be available. It provides simple means (isDone()
, get()
) to check completion and fetch the outcome. On the other hand, a Promise, gives you the wheels to manually set the results of the Future
, being its manufacturer, usually from another thread.
Example in Java that illustrates how CompletableFuture
can act as both Future and Promise:
The complete()
method is where the Promise magic happens, while get()
is the Future's way to say "patience is a virtue" and fetches the result.
Digging deeper: CompletableFuture
CompletableFuture
is a Future and a Promise in one. But it doesn't stop there — it stands out with a flamboyant API catering to an array of use-cases. It's the James Bond of the Future
world. With methods like thenApply
, thenCompose
, and thenAccept
, it facilitates asynchronous executions while maintaining an impressive savoir-faire and readability.
Here, we've initiated an asynchronous operation that later transforms the result and consumes the output all without blocking the current thread — like a ninja.
Promises in action
Promise
with CompletableFuture
is not a mere standalone object. It’s more like firing a starting gun for an asynchronous task you control. But be warned — promises are meant to be kept. A CompletableFuture
can be fulfilled once, and only once. Double fulfillment will make CompletableFuture
grumpy, resulting in an IllegalStateException
.
Synchronization concerns
When working with promises, be aware of potential race conditions. Promises can be fulfilled by any thread. Synchronizing this process or using thread-safe methods like complete()
, completeExceptionally()
, and cancel()
is akin to having a disciplined orchestra where no musician is overstepping their part.
Patterns and practices for async programming
- Promise composition: Combine multiple promises using
allOf
,anyOf
methods, control the flow of operation and handle results as they appear. - Common workflows: Abstract frequently used asynchronous flows into methods that return
CompletableFuture
. Drastically improves code maintainability and reducescopy-paste
mistrals. - Timeout safeguards: Always include a timeout mechanism to abort blocking tasks. It's like the emergency stop button, only cooler.
Advanced usage & tips
- Leverage descriptive methods: Utilize methods like
thenCombine
,thenCompose
,allOf
to effectively manage dependencies between tasks. - Graceful error-handling: Adopt error handling strategy using
handle
,exceptionally
, andwhenComplete
. Remember, even Batman has a contingency plan. - Thread execution: Learn when to supply an
Executor
to control the thread of operation and avoid the defaultForkJoinPool
when necessary. You're the conductor of this symphony.
In all the blissful chaos of promises and futures, remember to handle potential race conditions and always encapsulate operations that could lead to concurrency concerns.
Was this article helpful?