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.