Future And Callable
Callable is a function that will be executed asynchronously that can be used to submit to a Thread
Future is the result of this asynchronous function
Callable
Can be used to create a function to be call.
For example, we have
public static void main(String[] args) {
try {
Integer result = myCallableFunction().call();
System.out.println("result: " + result);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Callable<Integer> myCallableFunction() {
return () -> {
System.out.printf("%s working on this%n", Thread.currentThread().getName());
Thread.sleep(5000);
System.out.printf("%s finished on this%n", Thread.currentThread().getName());
return 5;
};
}
As a result we have
main working on this
main finished on this
result: 5
noteThis is still being executed synchronously
Future
To have a Future we need to make our Callable to be executed asynchronously.
CompletableFuture
One way is to use the CompletableFuture that will use a thread in java Common Pool
public static void main(String[] args) {
Future<Integer> result = myCallableFunction();
System.out.println("Some code executed in between");
try {
System.out.println("result: " + result.get());
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
public static CompletableFuture<Integer> myCallableFunction() {
return CompletableFuture.supplyAsync(() -> {
System.out.printf("%s working on this%n", Thread.currentThread().getName());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.printf("%s finished on this%n", Thread.currentThread().getName());
return 5;
});
}
In here, the callable function is wrapped with CompletableFuture.supplyAsync as a Supplier. As a result, this function will be executed on its own thread.
As a result, we have the following:
Some code executed in between
ForkJoinPool.commonPool-worker-1 working on this
ForkJoinPool.commonPool-worker-1 finished on this
result: 5
noteNote that
Callabledoes not work withCompletableFuture.supplyAsyncdirectly. In the example above, we used the same code inCallableas theSupplierinsidesupplyAsync. However,Callabledoes work withExecutorServicedirectly
ExecutorService
ExecutorService works with Callable directly. The submit() function takes in a Callable and returns a Future.
<T> Future<T> submit(Callable<T> task);
For example:
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<?> result = executorService.submit(() -> process());
executorService.shutdown();
try {
System.out.println("result: " + result.get());
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
public static int process() {
int random = (new Random()).nextInt(5000);
System.out.printf("%s working on this for %s%n" , Thread.currentThread().getName(), random);
try {
Thread.sleep(random);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
return random;
}
noteWhen we call
result.get()in both scenario ofCompletableFuture.supplyAsyncorExecutorService, the thread block indefinitely until it gets the result.
As a result, we have the following logs:
pool-1-thread-1 working on this for 2447
result: 2447
Note that in here we're not using the Common Pool anymore in contrast to the previous method.