The use of Future in java
The use of Future in java
Future is an interface introduced in java 1.5 that can be used to get asynchronous results easily. This article will explain how to use Future through specific examples.
Creating Future
As mentioned above, Future represents the result of asynchronous execution, which means that when the asynchronous execution is finished, the returned result will be saved in Future.
So when do we use Future? Generally speaking, when we execute a long-running task, using Future allows us to temporarily deal with other tasks, and then return the result when the long task is finished.
The scenarios where Future is often used are: 1. computationally intensive scenarios, 2. handling large amounts of data, 3. remote method calls, etc.
Next, we will use the ExecutorService to create a Future.
<T> Future<T> submit(Callable<T> task);
The above is a submit method defined in the ExecutorService, which takes a Callable parameter and returns a Future.
We use a thread to compute a square operation.
private ExecutorService executor
= Executors.newSingleThreadExecutor();
public Future<Integer> calculate(Integer input) {
return executor.submit(() -> {
System.out.println("Calculating..." + input);
Thread.sleep(1000);
return input * input;
});
}
The submit takes a Callable parameter, and the Callable needs to implement a call method and return the result. Here we use lamaba expressions to simplify this process.
Get the result from Future
We have created Future above, next we look at how to get the value of Future.
FutureUsage futureUsage = new FutureUsage();
Future<Integer> futureOne = futureUsage.calculate(20);
while(!futureOne.isDone()) {
System.out.println("Calculating...") ;
Thread.sleep(300);
}
Integer result = futureOne.get();
First we use Future.isDone() to determine if this asynchronous operation is finished, if it is we can directly call futureOne.get() to get the result of Futre.
Here futureOne.get() is a blocking operation, it will wait until the asynchronous execution is finished before returning the result.
If we don’t want to wait, future provides a method with time.
Integer result = futureOne.get(500, TimeUnit.MILLISECONDS);
If there is still a return from Future at the end of the wait time, a TimeoutException is thrown.
Cancel Future
If we submit an asynchronous program but want to cancel it, then we can do this.
Future<Integer> futureTwo = futureUsage.calculate(4);
boolean canceled = futureTwo.cancel(true);
Future.cancel(boolean) Pass in a boolean argument to choose whether to interrupt the running task.
If we cancel and then call the get() method again, a CancelationException will be thrown.
Running in a multi-threaded environment
If there are two computation tasks, first look at the result of running under single thread.
Future<Integer> future1 = futureUsage.calculate(10);
Future<Integer> future2 = futureUsage.calculate(100);
while (! (future1.isDone() && future2.isDone())) {
System.out.println(
String.format(
"future1 is %s and future2 is %s",
future1.isDone() ? "done" : "not done",
future2.isDone() ? "done" : "not done"
)
);
Thread.sleep(300);
}
Integer result1 = future1.get();
Integer result2 = future2.get();
System.out.println(result1 + " and " + result2);
Because we created the single thread pool by Executors.newSingleThreadExecutor(). So the result of the run is as follows.
Calculating... .10
future1 is not done and future2 is not done
future1 is not done and future2 is not done
The following is a summary of the calculations.
Future1 is not done and future2 is not done
Calculating... .100
future1 is done and future2 is not done
Future1 is done and future2 is not done
Future1 is done and future2 is not done
100 and 10000
If we use Executors.newFixedThreadPool(2) to create a multi-threaded pool, we get the following result.
calculating... .10
calculating... .100
future1 is not done and future2 is not done
future1 is not done and future2 is not done
Future1 is not done and future2 is not done
future1 is not done and future2 is not done
100 and 10000