Lesson 2
Callable and Future
Introduction to Callable and Future

Welcome back! In the previous lesson, we explored how to manage threads using Executors and Runnable. Now, we'll build on that foundation by introducing two advanced tools in Java's concurrency toolkit: Callable and Future. These components allow tasks to return results and handle exceptions, offering greater flexibility than Runnable. By the end of this lesson, you'll be able to handle asynchronous computations more effectively in your Java applications.

What You'll Learn

In this lesson, you'll gain an understanding of how to:

  • Use the Future interface to manage and retrieve results from asynchronous tasks.
  • Implement the Callable interface for tasks that return values or throw exceptions.
  • Submit Callable tasks to an ExecutorService and retrieve results using Future.

These concepts will greatly enhance your ability to handle asynchronous operations.

Understanding Future

The Future interface represents the result of an asynchronous computation. When you submit a task to an ExecutorService, it returns a Future object, which serves as a placeholder for the task's result. The Future provides several methods to monitor the status of the task, retrieve its result, and even cancel the task if necessary.

Let’s now look at an example that demonstrates submitting a Runnable task and monitoring its status using Future.

Java
1Future<?> future = executor.submit(() -> { 2 System.out.println("Task executed by " + Thread.currentThread().getName()); 3}); 4 5if (!future.isDone()) { 6 System.out.println("Task is still running..."); 7} 8 9executor.shutdown();

In this example:

  • The task is submitted using the submit() method, which returns a Future object. Unlike execute(), which does not return anything, submit() gives you more control over the task, allowing you to track its progress and retrieve a result if needed.

  • We use the isDone() method to check whether the task has completed execution. If the task is still running, it prints a message. future.isDone() checks if a Future task is complete without blocking the thread, unlike future.get(), which waits until the task finishes. It allows you to poll the task's status and act accordingly.

The Future object provides additional flexibility compared to execute() because it allows you to manage the task more effectively, especially when it involves results or long-running operations.

Understanding Callable

The Callable interface is similar to Runnable but with one major difference: it can return a result and throw exceptions. This makes Callable ideal for tasks that perform calculations, data retrieval, or any other operation that needs to return a value.

While Runnable tasks execute but don’t return anything, Callable tasks return a value that you can retrieve using the Future object.

Here’s an example of how to submit a Callable task and retrieve the result:

Java
1Callable<Integer> task = () -> { 2 System.out.println("Task executed by " + Thread.currentThread().getName()); 3 return 42; // Return result from the task 4}; 5 6Future<Integer> future = executor.submit(task); 7Integer result = future.get(); 8System.out.println("Result: " + result);

In this example:

  • A Callable task is defined to return the number 42.

  • The task is submitted to the ExecutorService using submit(), which returns a Future<Integer> since the task produces an Integer result.

  • The get() method is used to retrieve the result of the task. This method blocks the current thread until the task is completed and the result is available.

Callable tasks enable you to perform computations asynchronously and return values directly, making them a valuable tool for more complex operations.

Runnable vs Callable

Both Runnable and Callable are used to define tasks that can be executed by a thread or submitted to an ExecutorService. However, they serve different purposes:

  • Runnable: Used when you want to execute a task that doesn't return any result. It is suitable for simple tasks where you don’t need feedback.

  • Callable: Used when you need to execute a task that returns a result or may throw an exception. It is more flexible and powerful than Runnable but also requires the overhead of handling Future objects and managing task results.

Now that we've explored both Callable and Future, let's move forward to practical exercises to see these concepts in action!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.