Java Callable
Java
Callable interface uses Generic to define the return type of Object. Executors
class provide useful methods to execute Java Callable in a thread pool. Since
callable tasks run in parallel, we have to wait for the returned Object.
Java Future
Java
Callable tasks return java.util.concurrent.Future object. Using Java Future
object, we can find out the status of the Callable task and get the returned
Object. It provides get() method that can wait for the Callable to finish and
then return the result.
Java
Future provides cancel() method to cancel the associated Callable task. There
is an overloaded version of get() method where we can specify the time to wait
for the result, it’s useful to avoid current thread getting blocked for a longer
time. There are isDone() and isCancelled() methods to find out the current
status of the associated Callable task.
A simple example of Java Callable task that returns the name of the thread executing
the task after one second. We are using the Executor framework to execute 20
tasks in parallel and use Java Future to get the result of the submitted
tasks.
package com.algorithmforum.thread;
import
java.util.ArrayList;
import
java.util.Date;
import
java.util.List;
import
java.util.concurrent.Callable;
import
java.util.concurrent.ExecutionException;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
java.util.concurrent.Future;
public class CallableTest {
public static void
main(String args[]) {
// Get ExecutorService from Executors utility class, thread pool
size is 5
ExecutorService
executor = Executors.newFixedThreadPool(5);
// Create a list to hold the Future object associated with Callable
List>
futureList = new
ArrayList>();
/**
* Create MyCallable instance using Lambda
expression which returns
* the thread name executing this callable task
*/
Callable
callable = () -> {
Thread.sleep(2000);
return Thread.currentThread().getName();
};
/**
* Submit Callable tasks to be executed by
thread pool
* Add Future to the list, we can get a return
value using Future
**/
for (int i = 0; i < 20; i++) {
Future
future = executor.submit(callable);
futureList.add(future);
}
/**
* Print the return value of Future, notice the
output delay
* in console because Future.get() waits for the task to get completed
**/
for (Future future : futureList) {
try {
System.out.println(new Date() + " | " + future.get());
}
catch (InterruptedException |
ExecutionException e) {
e.printStackTrace();
}
}
// shut down the executor service.
executor.shutdown();
}
}
Once
we execute the above program, we can notice the delay in output because of java
Future get() method waits for the java callable task to complete. Also, notice
that there are only 5 threads executing these tasks.
Here
is the snippet of the output of the above program.
Sat Jun 01 15:37:10 IST 2019 |
pool-1-thread-1
Sat Jun 01 15:37:12 IST 2019 |
pool-1-thread-2
Sat Jun 01 15:37:12 IST 2019 |
pool-1-thread-3
Sat Jun 01 15:37:12 IST 2019 |
pool-1-thread-4
Sat Jun 01 15:37:12 IST 2019 |
pool-1-thread-5
Sat Jun 01 15:37:12 IST 2019 |
pool-1-thread-2
Sat Jun 01 15:37:14 IST 2019 |
pool-1-thread-1
Sat Jun 01 15:37:14 IST 2019 |
pool-1-thread-4
Sat Jun 01 15:37:14 IST 2019 |
pool-1-thread-5
Sat Jun 01 15:37:14 IST 2019 |
pool-1-thread-3
Sat Jun 01 15:37:14 IST 2019 |
pool-1-thread-1
Sat Jun 01
15:37:16 IST 2019 | pool-1-thread-4
...
Note
What
if we want to override some of the methods of Java Future interface, for
example overriding get() method to timeout after some default time rather than
waiting indefinitely, in this case, Java FutureTask class comes handy that is
the base implementation of Future interface. Check out Java FutureTask Example
to learn more about this class.