Say I have a queue full of tasks which I need to submit to an executor service. I want them processed one at a time. The simplest way I can think of is to:
- Take a task from the queue
- Submit it to the executor
- Call .get on the returned Future and block until a result is available
- Take another task from the queue...
However, I am trying to avoid blocking completely. If I have 10,000 such queues, which need their tasks processed one at a time, I'll run out of stack space because most of them will be holding on to blocked threads.
What I would like is to submit a task and provide a call-back which is called when the task is complete. I'll use that call-back notification as a flag to send the next task. (functionaljava and jetlang apparently use such non-blocking algorithms, but I can't understand their code)
How can I do that using JDK's java.util.concurrent, short of writing my own executor service?
(the queue which feeds me these tasks may itself block, but that is an issue to be tackled later)
Just to add to Matt's answer, which helped, here is a more fleshed-out example to show the use of a callback.
The output is:
Use Guava's listenable future API and add a callback. Cf. from the website :
You could extend
FutureTask
class, and override thedone()
method, then add theFutureTask
object to theExecutorService
, so thedone()
method will invoke when theFutureTask
completed immediately.You may use a implementation of Callable such that
where CallbackInterface is something very basic like
and now the main class will look like this
ThreadPoolExecutor
also hasbeforeExecute
andafterExecute
hook methods that you can override and make use of. Here is the description fromThreadPoolExecutor
's Javadocs.This is an extension to Pache's answer using Guava's
ListenableFuture
.In particular,
Futures.transform()
returnsListenableFuture
so can be used to chain async calls.Futures.addCallback()
returnsvoid
, so cannot be used for chaining, but is good for handling success/failure on an async completion.NOTE: In addition to chaining async tasks,
Futures.transform()
also allows you to schedule each task on a separate executor (Not shown in this example).