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)
Use a
CountDownLatch
.It's from
java.util.concurrent
and it's exactly the way to wait for several threads to complete execution before continuing.In order to achieve the callback effect you're looking after, that does require a little additional extra work. Namely, handling this by yourself in a separate thread which uses the
CountDownLatch
and does wait on it, then goes on about notifying whatever it is you need to notify. There is no native support for callback, or anything similar to that effect.EDIT: now that I further understand your question, I think you are reaching too far, unnecessarily. If you take a regular
SingleThreadExecutor
, give it all the tasks, and it will do the queueing natively.Define a callback interface to receive whatever parameters you want to pass along in the completion notification. Then invoke it at the end of the task.
You could even write a general wrapper for Runnable tasks, and submit these to
ExecutorService
. Or, see below for a mechanism built into Java 8.With
CompletableFuture
, Java 8 included a more elaborate means to compose pipelines where processes can be completed asynchronously and conditionally. Here's a contrived but complete example of notification.Simple code to implement
Callback
mechanism usingExecutorService
output:
Key notes:
newFixedThreadPool(5)
withnewFixedThreadPool(1)
If you want to process next task after analysing the result from
callback
of previous task,just un-comment below lineYou can replace
newFixedThreadPool()
with one ofdepending on your use case.
If you want to handle callback method asynchronously
a. Pass a shared
ExecutorService or ThreadPoolExecutor
to Callable taskb. Convert your
Callable
method toCallable/Runnable
taskc. Push callback task to
ExecutorService or ThreadPoolExecutor
If you want to make sure that no tasks will run at the same time then use a SingleThreadedExecutor. The tasks will be processed in the order the are submitted. You don't even need to hold the tasks, just submit them to the exec.
In Java 8 you can use CompletableFuture. Here's an example I had in my code where I'm using it to fetch users from my user service, map them to my view objects and then update my view or show an error dialog (this is a GUI application):
It executes asynchronously. I'm using two private methods:
mapUsersToUserViews
andupdateView
.