Example of Java Future
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
int result = 0;
for (int i = 0; i < 10; i++) {
result += i;
}
return result;
});
// Do some other work
System.out.println("Doing other work...");
// Get the result of the task
try {
int result = future.get();
System.out.println("Task result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executor.shutdown();
In this example, we create an `ExecutorService` using the `Executors.newSingleThreadExecutor()` method. This creates a single-threaded executor, which means that tasks will be executed one at a time.
We then submit a task to the executor using the `submit()` method. The task calculates the sum of the numbers from 0 to 9 and returns the result as an `Integer`.
While the task is running, we can do some other work in the main thread. In this case, we just print a message to the console.
To get the result of the task, we call the `get()` method on the `Future` object. This will block until the task is done and return the result. If the task throws an exception, `get()` will throw an `ExecutionException`.
Finally, we shut down the executor using the `shutdown()` method to release any resources it was using.
Methods of the Future Interface
The `Future` interface provides several methods that allow you to manage and retrieve the result of an asynchronous task. Here are some of the most commonly used methods:
1. `get()`: This method retrieves the result of the task. If the task is not yet complete, it will block until the task is done. If the task throws an exception, `get()` will throw an `ExecutionException`.
2. `get(long timeout, TimeUnit unit)`: This method is similar to `get()`, but it allows you to specify a timeout value. If the task does not complete within the specified time, a `TimeoutException` will be thrown.
3. `cancel(boolean mayInterruptIfRunning)`: This method attempts to cancel the task. If the task has not yet started, it will not be executed. If the task is already running, the `mayInterruptIfRunning` parameter determines whether the thread executing the task should be interrupted.
4. `isCancelled()`: This method returns `true` if the task was cancelled before it completed normally.
5. `isDone()`: This method returns `true` if the task has completed, either normally or by being cancelled.
Let’s discuss an example of how to use some of these methods:
Future<String> future = executor.submit(() -> {
// Perform some task
return "Task result";
});
// Check if the task is done
if (future.isDone()) {
System.out.println("Task is already done!");
} else {
System.out.println("Task is still running...");
}
// Try to retrieve the result, waiting up to 5 seconds
try {
String result = future.get(5, TimeUnit.SECONDS);
System.out.println("Task result: " + result);
} catch (TimeoutException e) {
System.out.println("Task timed out!");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
In this example, we first check if the task is done using the `isDone()` method. If it is, we print a message saying so. If not, we print a message saying the task is still running.
We then try to retrieve the result of the task using the `get(long timeout, TimeUnit unit)` method, waiting up to 5 seconds for the task to complete. If the task completes within that time, we print the result. If the task times out, we print a message saying so. If the task throws an exception, it will be caught and printed.
Using Future in Asynchronous Programming
Java Future is a powerful tool for writing asynchronous code. It allows you to start a task in the background and continue with other work while the task is running. This can greatly improve the performance and responsiveness of your application.
Let’s see an example of Java Future in an asynchronous application:
public class AsyncExample {
private ExecutorService executor = Executors.newFixedThreadPool(10);
public Future<String> fetchData(String url) {
return executor.submit(() -> {
// Fetch data from the URL
String data = // ...
return data;
});
}
public void processData(List<String> urls) {
List<Future<String>> futures = new ArrayList<>();
// Start a task for each URL
for (String url : urls) {
futures.add(fetchData(url));
}
// Process the results as they become available
for (Future<String> future : futures) {
try {
String data = future.get();
// Process the data
// ...
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
In this example, we have an `AsyncExample` class that fetches data from a list of URLs asynchronously.
The `fetchData()` method takes a URL and returns a `Future<String>` that represents the result of fetching the data from that URL. The actual fetching is done in a background task submitted to an `ExecutorService`.
The `processData()` method takes a list of URLs and fetches the data for each one asynchronously. It does this by calling `fetchData()` for each URL and storing the resulting `Future` objects in a list.
It then processes the results as they become available by calling `get()` on each `Future`. This will block until the result is ready, but since we have multiple tasks running in the background, the overall processing can happen in parallel.
Getting Result
One of the key features of Java Future is the ability to get the result of an asynchronous task. The `get()` method is used for this purpose.
For example :
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
// Simulate a long-running task
Thread.sleep(2000);
return 42;
});
// Do some other work while the task is running
System.out.println("Doing other work...");
// Get the result of the task
try {
Integer result = future.get();
System.out.println("Task result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executor.shutdown();
In this example, we submit a task to the executor that simulates a long-running operation by sleeping for 2 seconds (using `Thread.sleep(2000)`) and then returning the value `42`.
After submitting the task, we can continue doing other work in the main thread. In this case, we just print a message to the console.
To get the result of the task, we call `future.get()`. This will block until the task is complete and then return the result (in this case, `42`).
If the task throws an exception, `get()` will throw an `ExecutionException`. If the thread waiting for the result is interrupted, `get()` will throw an `InterruptedException`. It's important to handle these exceptions appropriately.
Note that calling `get()` will block indefinitely if the task never completes. If you want to avoid this, you can use the `get(long timeout, TimeUnit unit)` method to specify a maximum time to wait for the result.
For example:
try {
Integer result = future.get(5, TimeUnit.SECONDS);
System.out.println("Task result: " + result);
} catch (TimeoutException e) {
System.out.println("Task timed out!");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
In this case, if the task doesn't complete within 5 seconds, a `TimeoutException` will be thrown.
Cancel an Asynchronous Task
Sometimes you may need to cancel an asynchronous task before it completes. Java Future provides the `cancel()` method for this purpose.
For example:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
int result = 0;
for (int i = 0; i < 100; i++) {
result += i;
Thread.sleep(100);
}
return result;
});
// Cancel the task after 1 second
Thread.sleep(1000);
future.cancel(true);
// Check if the task was cancelled
if (future.isCancelled()) {
System.out.println("Task was cancelled");
} else {
System.out.println("Task completed normally");
}
executor.shutdown();
In this example, we submit a task to the executor that sums the numbers from 0 to 99, sleeping for 100 milliseconds between each addition. This simulates a long-running task that can be interrupted.
After submitting the task, we sleep the main thread for 1 second and then call `future.cancel(true)`. The `true` argument means that the task should be interrupted if it's currently running.
We then check if the task was cancelled using the `isCancelled()` method. In this case, since we cancelled the task after 1 second, it's likely that the task was indeed cancelled and didn't complete normally.
It's important to note that `cancel()` doesn't guarantee that the task will stop immediately. If the task is not responsive to interruption (for example, if it's in a blocking operation that doesn't check for interruption), it may continue running even after `cancel()` is called.
Also, if the task has already completed by the time `cancel()` is called, the cancellation request will have no effect.
After cancelling a task, calling `get()` on the `Future` will throw a `CancellationException`.
For example:
try {
Integer result = future.get();
} catch (CancellationException e) {
System.out.println("Task was cancelled");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
Check if an Asynchronous Task is Done
Sometimes you may want to check if an asynchronous task has completed without blocking to wait for its result. Java Future provides the `isDone()` method for this purpose.
For example :
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
// Simulate a long-running task
Thread.sleep(2000);
return 42;
});
// Check if the task is done
if (future.isDone()) {
System.out.println("Task has completed");
} else {
System.out.println("Task is still running");
}
// Do some other work
System.out.println("Doing other work...");
// Check again if the task is done
if (future.isDone()) {
System.out.println("Task has completed");
try {
Integer result = future.get();
System.out.println("Task result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
} else {
System.out.println("Task is still running");
}
executor.shutdown();
In this example, we submit a task to the executor that sleeps for 2 seconds (simulating a long-running operation) and then returns the value `42`.
Immediately after submitting the task, we check if it's done using `future.isDone()`. Since the task takes 2 seconds to complete, it's very likely that it won't be done at this point, so we print "Task is still running".
We then do some other work (in this case, just print a message), and then check again if the task is done. This time, it's likely that the 2 seconds have passed and the task has completed, so we print "Task has completed" and get the result of the task using `future.get()`.
The `isDone()` method returns `true` if the task has completed, whether it completed normally, threw an exception, or was cancelled. It returns `false` if the task is still running.
Note that `isDone()` does not block. It returns immediately with the current status of the task.
This method is useful when you want to do something based on the completion of the task, but you don't want to block your main thread to wait for the result.
For example, you might use `isDone()` to provide a progress indicator to the user, or to start a new task when a previous one has completed.
Check if an Asynchronous Task is Cancelled
In addition to checking if a task is done, you can also specifically check if a task was cancelled using the `isCancelled()` method provided by Java Future.
For example :
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(() -> {
int result = 0;
for (int i = 0; i < 100; i++) {
result += i;
Thread.sleep(100);
}
return result;
});
// Cancel the task after 1 second
Thread.sleep(1000);
future.cancel(true);
// Check if the task was cancelled
if (future.isCancelled()) {
System.out.println("Task was cancelled");
} else {
System.out.println("Task was not cancelled");
}
// Attempting to get the result will throw a CancellationException
try {
Integer result = future.get();
} catch (CancellationException e) {
System.out.println("Attempting to get the result of a cancelled task throws a CancellationException");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executor.shutdown();
This example is similar to the one in the "Cancel an Asynchronous Task" section. We submit a task to the executor, then cancel it after 1 second.
We then use `future.isCancelled()` to check if the task was indeed cancelled. This method returns `true` if the task was cancelled before it completed normally.
Note that `isCancelled()` will return `true` even if the task was cancelled after it had already completed. In other words, it doesn't tell you whether the cancellation actually had any effect, only that `cancel()` was called at some point.
After a task has been cancelled, attempting to `get()` its result will throw a `CancellationException`. This is demonstrated in the example above.
The `isCancelled()` method is useful when you need to take different actions based on whether a task completed normally or was cancelled. For example, you might use it to clean up resources that are no longer needed if a task was cancelled.
Example of Java Future
Java
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 FutureExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
// Submit a task and get its Future
Future<Integer> future1 = executor.submit(new Callable<Integer>() {
@Override
public Integer call() throws InterruptedException {
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
Thread.sleep(10);
}
return sum;
}
});
// Submit another task and get its Future
Future<Double> future2 = executor.submit(new Callable<Double>() {
@Override
public Double call() throws InterruptedException {
double sum = 0;
for (double i = 0; i < 100; i++) {
sum += i;
Thread.sleep(10);
}
return sum;
}
});
// Check if the tasks are done
while (!future1.isDone() || !future2.isDone()) {
System.out.println("Tasks are not done yet...");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Get the results of the tasks
try {
Integer result1 = future1.get();
Double result2 = future2.get();
System.out.println("Task 1 result: " + result1);
System.out.println("Task 2 result: " + result2);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// Submit a task and cancel it
Future<String> future3 = executor.submit(new Callable<String>() {
@Override
public String call() throws InterruptedException {
Thread.sleep(2000);
return "This task was cancelled";
}
});
future3.cancel(true);
// Check if the task was cancelled
if (future3.isCancelled()) {
System.out.println("Task 3 was cancelled");
} else {
try {
String result3 = future3.get();
System.out.println("Task 3 result: " + result3);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
executor.shutdown();
}
}

You can also try this code with Online Java Compiler
Run Code
Output
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Tasks are not done yet...
Task 1 result: 4950
Task 2 result: 4950.0
Task 3 was cancelled
In this example, we create an `ExecutorService` with a fixed thread pool of size 2.
We then submit two tasks to the executor, each of which calculates a sum in a slightly different way. We get the `Future` objects for these tasks.
We use a while loop to check if the tasks are done using the `isDone()` method. The loop keeps running until both tasks are done. Inside the loop, we print a message and sleep for a short time to avoid excessive CPU usage.
Once both tasks are done, we get their results using the `get()` method and print them.
We then submit a third task and immediately cancel it using `cancel(true)`. We check if the task was cancelled using `isCancelled()` and print a message if it was.
Finally, we shut down the executor.
This example showcases several key features of Java Future:
- Submitting tasks to an executor and getting their `Future` objects.
- Checking if tasks are done using `isDone()`.
- Getting the results of tasks using `get()`.
- Cancelling a task using `cancel()`.
- Checking if a task was cancelled using `isCancelled()`.
Frequently Asked Questions
What happens if I call get() on a Future and the task hasn't completed yet?
The get() method will block until the task completes, and then it will return the result.
Can I cancel a task that has already completed?
Yes, you can call cancel() on a Future even if the task has already completed, but it will have no effect.
What's the difference between isDone() and isCancelled()?
isDone() returns true if the task has completed, whether normally, by throwing an exception, or by being cancelled. isCancelled() returns true only if the task was cancelled before it completed normally.
Conclusion
In this article, we have learned about Java Future, a powerful tool for managing asynchronous tasks. We've seen how to submit tasks to an executor, get their Future objects, check if tasks are done, get task results, and cancel tasks. We've also looked at several methods provided by the Future interface, such as get(), isDone(), isCancelled(), and cancel(). Java Future allows you to write more efficient and responsive asynchronous code, especially when dealing with time-consuming I/O operations.
You can also practice coding questions commonly asked in interviews on Coding Ninjas Code360.
Also, check out some of the Guided Paths on topics such as Data Structure and Algorithms, Competitive Programming, Operating Systems, Computer Networks, DBMS, System Design, etc., as well as some Contests, Test Series, and Interview Experiences curated by top Industry Experts.