Java executors: how to be notified, without blocking, when a task completes?
To get notified of your ExecutorService tasks completion without blocking, attach callbacks using CompletableFuture. Use thenRun
for a no-argument callback or thenAccept
for callbacks that work with the task result.
In this snippet, we create a task to return 42
, submit it with the ExecutorService
, and then thenAccept
is used to print the result once it's available — all without blocking the main thread.
Supercharging with CompletableFuture
Completing tasks asynchronously isn't just about notifications — it's about having more control and flexibility. Let's explore:
Attaching simple callbacks to tasks
When a task completes, you may want to execute an action. In this case, thenRun
or thenAccept
can be used to chain tasks.
Multi-tasking with callbacks
When tasks are interdependent, thenCompose
or thenCombine
chains them together.
Handling exceptions in callbacks
exceptionally
allows us to recover from exceptions, ensuring the task flow is not interrupted.
Instant callback on task completion
Override the done()
method by extending FutureTask, and voila! You've got a hook into the completion event:
Expanding your arsenal with callbacks
The power of Guava's ListenableFuture
Guava's ListenableFuture and ListeningExecutorService provide you with control you didn't know you needed. Using them, you can register callbacks:
ThreadPoolExecutor hooks for intelligence
Gain valuable insights or take actions pre or post task execution with ThreadPoolExecutor hooks, beforeExecute and afterExecute :
Consistent performance with fixed thread pool
Ensure predictable performance by using a fixed thread pool.
Taking action after an ExecutorService terminations
Perform actions after the ExecutorService
has been shut down by overriding terminated():
Artfully crafting tasks and callbacks
Keeping your asynchronous tasks and callbacks well-organized will bolster maintainability:
- Use the Callable interface to define tasks promising tasty return values.
- Release resources religiously in tasks using a try-finally structure.
- Chain operations with thenApply for taking a gander at results.
- Keep chain intact by healing a broken link with exceptionally when there's an exception.
Was this article helpful?