Java is an incredibly popular language, and learning its fundamentals can significantly advance a programmer’s career. Today, we are looking at two different ways of executing tasks in Java—Callable and Runnable. In this article, we will discuss the differences between the two, provide some examples of using them, and offer some advice on when each should be utilized.
Understanding the Differences Between Callable and Runnable
At their core, Java Callable and Runnable both allow us to run tasks in the background without blocking or waiting on the main thread. The main differences between them are:
- Callable completes a particular calculation, and returns the result to the executor (the code which runs the Callable). Callable supports checked exceptions and often use Generics when declaring the return type of the callable.
- Runnable is void and will not return any value. It just completes a specific action such as sending a notification. Runnable does not support checked exceptions.
When deciding which to use, it is important to consider the type of task you are trying to accomplish. If you need to return a value, then Callable is the better choice. If you just need to perform an action, then Runnable is the better choice. Additionally, if you need to throw a checked exception, then Callable is the only option.
Advantages and Disadvantages of Each
Advantages and disadvantages of each should be considered when choosing which to use.
- Advantages of Callable:
- Can return a result.
- Supports checked exceptions.
- When a large number of tasks need to be completed that require some sort of calculation, Callable can reduce the amount of threads needed and they can be easily reused.
- Disadvantages of Callable:
- Requires additional coding when compared to simply utilizing Runnable.
- The overhead for Callable is more than for Runnable.
- Advantages of Runnable:
- Runnable does not require any additional coding compared to Callable which reduces development time.
- The performance overhead for executing is lower than for Callable as it does not need to return a result.
- Disadvantages of Runnable:
- Will not return a result.
- Does not support checked exceptions meaning additional logic must be added to catch unchecked exceptions when using this process.
When deciding which to use, it is important to consider the complexity of the task and the resources available. If the task is relatively simple and resources are limited, then Runnable may be the best option. However, if the task is more complex and resources are available, then Callable may be the better choice.
When to Use Callable or Runnable
Choosing which method to use can be difficult at times. Generally, if you need to complete some sort of calculation that returns a result then Callable would be the best option. However, if you just need to complete some action such as a notification or an update, then Runnable should be used.
It is worth noting that if the calculation that the Callable needs to complete is relatively small and will only run once then using a Runnable may be more efficient in terms of performance. On the other hand, if the calculation will be running multiple times and needs to be reused or if the calculation returns something that is to be used externally, then using the Callable method may be better as these processes are more memory efficient.
It is important to consider the complexity of the task when deciding which method to use. If the task is relatively simple and does not require a return value, then Runnable is the best option. However, if the task is more complex and requires a return value, then Callable is the best choice.
What is Callable?
A Callable is an interface that enables a concurrent task to return a result. This makes for an efficient way of complete calculations that also allows for reuse. A Callable is executed by submitting it to an ExecutorService which handles the threading for the Callables allowing for more efficient and faster completion of multiple tasks.
You can create your own Callables by creating a class that implements the Callable interface. The call() method is where the Callable’s execution code should go and you can return any object here. A simple example is provided below:
public class MyCallable implements Callable<Long> { @Override public Long call() throws Exception { // Do your calculations here and return a value return result; } }
Once you have created your Callable, you can submit it to an ExecutorService to be executed. The ExecutorService will then manage the threading of the Callable and return the result when it is complete. This makes it easy to execute multiple tasks in parallel and get the results quickly.
What is Runnable?
Runnable is a popular interface used in Java to execute tasks asynchronously. It does not support any return type and as a result, does not return a result but rather just executes a specific action. It is recommended for any jobs that do not require a return type such as updating data, sending notifications or printing messages.
You can create your own runnables by creating a class that implements the Runnable interface. The run() method is where your code should go that you wish to execute and upon completion, simply return nothing (void) as no result needs to be returned. A simple example is provided below:
public class MyRunnable implements Runnable { @Override public void run() { // Do your task here } }
Implementing Callables and Runnables in Java Code
Once you’ve defined your interface for either a Callable or Runnable then you can submit the instances of these classes to an ExecutorService for execution.
An example of doing this with a Runnable task is provided below:
ExecutorService executorService = Executors.newFixedThreadPool(10); MyRunnable myRunnable = new MyRunnable(); executorService.submit(myRunnable); executorService.shutdown();
An example of doing this with a callable task is provided below:
ExecutorService executorService = Executors.newFixedThreadPool(10); MyCallable myCallable = new MyCallable(); Future<Long> future = executorService.submit(myCallable); //do something else //get the result from the future Long result = future.get(); executorService.shutdown();
Comparing the Performance of Java Callables and Runnables
In terms of performance, depending on the tasks being completed, both of these processes can perform equally well or showing minimal performance difference. But it is important to note that if you are using Callables instead of Runnables you can expect some additional overhead associated with potential checks against checked exceptions or passing the result back to the ExecutorService.
Conclusion
Learning the ins-and-outs of Java can be daunting but understanding terms like callables and runnables is key to becoming an efficient programmer. As we discussed in this article, understanding the differences between callables and runnables and when each should be used is essential in order to create effective Java code.