Callable and Runnable
What is the difference between Runnable and Callable in Java?
Multithreading is a major aspect of java language.
Both interfaces are designed to represent a task that can be run by multiple threads. They are implemented by the classes who wish to execute something (a piece of work) in a different thread of execution (than the thread that the class is running in). Runnable and Callable both run on a different thread than the calling thread. But Callable can return a value and Runnable cannot.
Runnable is the core interface provided for representing multithreaded tasks.
This interface is implemented by the Thread class as well and it’s a common protocol for all the objects who wish to execute in a different thread. It’s one of the ways of creating threads in Java. The other way to create a thread is by subclassing the Thread class. A class implementing Runnable interface can simply pass itself to create a Thread instance and can run thereafter. This eliminates the need of subclassing the Thread class for the purpose of executing the code in a separate thread.
As long as we don’t wish to override other methods of the Thread class, it may be a better idea to implement the Runnable interface to enable multithreading capabilities to a class than enabling the same by extending the Thread class.
Callable was introduced in Java 1.5 as part of the Executor framework to handle use-cases that Runnable
does not support.
java.util.concurrent
Interface Callable<V>
Type Parameters:
V - the result type of method call
In theory, the Java team could have changed the signature of the Runnable.run()
method instead of introducing the Callable
interface, but this would have broken binary compatiblity with pre-1.5 code.
Runnable
interface cannot do everything that Callable
does.
There are use-cases where a task doesn’t need to return a result or throw a checked exception. For those use-cases, using Runnable is more concise than using Callable<Void> and returning a dummy (null) value from the call() method.
For use-cases where catching and handling exceptions is important, use Callable.
<../multithreading/src/main/java/com/example/LaunchingCallableUsingExecutorService.java>
Use Runnable for fire and forget calls. Use Callable to verify the result.
- Instances of the classes that implement Runnable or Callable interfaces are potentially executed by another thread.
- Instance of both Callable and Runnable interfaces can be executed by ExecutorService via submit() method.
- Both are functional interfaces (that provide single abstract methods called run and call respectively) and can be used in Lambda expressions since Java8.
Runnable | Callable<T> |
---|---|
Introduced in Java 1.0 of java.lang | Introduced in Java 1.5 of java.util.concurrent library |
java.lang package |
java.util.concurrent package |
Runnable tasks can be run using the Thread class or ExecutorService | Callables can be run only using ExecutorService |
Runnable has run() method | Callable has call() method |
Runnable.run() does not return anyting (returns void) | Callable.call() can return a value |
No way to propagate checked exceptions | Callable’s call()“throws Exception” clause so we can easily propagate checked exceptions further |
Runnable use execute() method to put in task queue | Callable use submit() method to put in task queue |
Runnable cannot be parametrized | Callable is a parametrized type whose type parameter indicates the return type of its run method. call() method takes no arguments and returns a result of type V. |
ExecutorService.execute(Runnable) or ExecutorService.submit(Runnable task) | Executor.submit(Callable<T> task) or ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks) |
Use cases
Runnable
If you have a fire and forget task then use Runnable. Put your code inside a Runnable and when the run() method is called, you can perform your task. The calling thread really does not care when you perform your task.
Callable
If you are trying to retrieve a value from a task, then use Callable. Now callable on its own will not do the job. You will need a Future that you wrap around your Callable and get your values on future.get (). Here the calling thread will be blocked till the Future comes back with results which in turn is waiting for Callable’s call() method to execute.
So think about an interface to a target class where you have both Runnable and Callable wrapped methods defined. The calling class will randomly call your interface methods not knowing which is Runnable and which is Callable. The Runnable methods will execute asynchronously, till a Callable method is called. Here the calling class’s thread will block since you are retrieving values from your target class.
NOTE : Inside your target class you can make the calls to Callable and Runnable on a single thread executor, making this mechanism similar to a serial dispatch queue. So as long as the caller calls your Runnable wrapped methods the calling thread will execute really fast without blocking. As soon as it calls a Callable wrapped in Future method it will have to block till all the other queued items are executed. Only then the method will return with values. This is a synchronization mechanism.
Callable is relatively new interface and it was introduced as a part of concurrency package. Both Callable and Runnable can be used with executors. Class Thread (that implements Runnable itself) supports Runnable only.
You can still use Runnable with executors. The advantage of Callable that you can send it to executor and immediately get back Future result that will be updated when the execution is finished. The same may be implemented with Runnable, but in this case you have to manage the results yourself. For example you can create results queue that will hold all results. Other thread can wait on this queue and deal with results that arrive.
Other differences
You can pass Runnable to create a Thread. But you can’t create new Thread by passing Callable as parameter. You can pass Callable only to ExecutorService instances.
Callable can be passed to invokeAll method unlike Runnable. Methods invokeAny and invokeAll perform the most commonly useful forms of bulk execution, executing a collection of tasks and then waiting for at least one, or all, to complete
We can not pass/use Callable to an individual thread for execution i.e. Callable can be used only in Executor Framework. But, Runnable can be passed to an individual thread for execution (new Thread(new CustomRunnable())), as well as can be used in Executor Framework.
Gotcha’s
What happens when you call run() method of a Runnable class without creating a new class or creating an ExecutorService?
It will run in the same thread where main() is running.
<../multithreading/src/main/java/com/example/HelloRunnableFromSameThread.java>