I have some tasks defined as Runnable
objects. I want to invoke those tasks by using the invokeAll
or invokeAny
methods on ExecutorService
.
The problem is that those methods take a collection of Callable
objects (tasks that return a result) rather than a collection of Runnable
objects (tasks that do not return a result).
Can I convert or wrap my Runnable
objects to act as Callable
objects without having to rewrite my task class?
Executors.callable
Easy to solve.
The Executors
utility class offers a pair of callable
methods that transform a Runnable
into a Callable
.
One method produces null
as the result of the task. The other returns your specified object as the result.
Method | Description |
---|---|
Executors.callable(Runnable task) |
runs task, returns null |
Executors.callable(Runnable task, T result) |
runs task, returns the passed result |
Let's start with some Runnable
objects.
Collection<Runnable> runnables =
List.of(
new MyRunnable(),
new MyRunnable(),
new MyRunnable()
);
Convert each Runnable
object into a Callable
object that returns null
as the result obtained via a Future
object.
We can use streams to write a one-liner for converting Runnable
objects to Callable
objects.
Collection<Callable<Object>> tasks = runnables.stream().map(Executors::callable).toList();
If you are not comfortable with streams, use for
loop.
Collection<Callable<Object>> tasks = new ArrayList<>();
for (Runnable runnable : runnables) {
Callable<Object> callable = Executors.callable(runnable);
tasks.add(callable);
}
Let's execute those Callable
task objects.
Here we use try-with-resources syntax to automatically close the ExecutorService
after it completes all submitted tasks.
try (ExecutorService executorService = Executors.newCachedThreadPool()) {
try {
List<Future<Object>> futures = executorService.invokeAll(tasks);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
When run:
Running `run` method of `MyRunnable` id: bbc1b37a-dfc9-43da-8245-6a451b1d5517 at 2024-06-03T23:32:04.505167Z
Running `run` method of `MyRunnable` id: fec26a2f-3b11-413b-a6c3-3bc802874302 at 2024-06-03T23:32:04.505167Z
Running `run` method of `MyRunnable` id: d71fefe3-3387-4743-9c7d-20c338b84a33 at 2024-06-03T23:32:04.505163Z
IF we were to loop through the futures
collection, and call get
, we would receive a null
from each of them.
By the way, notice how output from System.out.println
does not necessarily appear on the console in chronological order when called across threads.