Callable is different from Runnable

The characteristics of the Runnable

First, the Runnable interface. In the procedure we use, we simply implement the interface and implement the run() method, which has no return value for the method. This means that we can only write our asynchronous logic in the body of the run method, not get the return value. If you want to retrieve the execution result, the method is tedious because you can’t retrieve the result from a separate thread. A shared variable needs to be maintained to process the results. Second, the run method cannot throw a non-runtime exception. The run method does not throw exceptions. That is, if the exception scenario is not run, the try-catch method must be used when writing the code.

class Task implements Runnable {
   
   @Override
   public void run(a) {
       try {
           throw new IOException();
       } catch(IOException e) { e.printStackTrace(); }}}Copy the code

If it is a RuntimeException, the normally used scenario may not throw it, as it would affect the execution of our thread if placed in the run method. For example, we will now implement tasks with the Runnable interface, using thread pools and executing them regularly. If the Runnable interface is implemented internally.

class Task implements Runnable {

    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getId() + ":" + Thread.currentThread().getName() + ":" + "task....");
            throw newRuntimeException(); }}Copy the code

main

public static void main(String[] args) {
    ScheduledExecutorService service = new ScheduledThreadPoolExecutor(1);
    service.scheduleWithFixedDelay(new Task(), 1.1, TimeUnit.SECONDS);
}
Copy the code

The scheduled task does not proceed further and the specified exception is not thrown. It would be difficult to locate the problem if we had normal business code written here.

Another way is just like checking for exceptions. Throws the exception we caught

class Task implements Runnable {

    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getId() + ":" + Thread.currentThread().getName() + ":" + "task....");
        try {
            throw new RuntimeException();
        } catch (RuntimeException e){
            throw newRuntimeException(); }}}Copy the code

The above is the Runable interface can be said to be defective. Why is this a problem? Take a look at the definition of the Runnable interface:

public interface Runnable {

   public abstract void run(a);

}
Copy the code

Runnable is an interface and has only one method inside it, called public Abstract void Run (). This method already specifies that the return type of the run() method is void, and it does not declare to throw any exceptions. So, when we implement and rewrite the method, we cannot change either the return value type or the description of the exception thrown, because we are syntactically prohibited from doing so when we implement the method.

  • Why is Runnable designed this way

Further down the line, why did Java design it this way?

Assuming that the run() method can return a return value, or that it can throw an exception, doesn’t help because we don’t have a way to catch and handle it in the outer layer, because the classes that call the run() method (such as the Thread class and Thread pool) are directly provided by Java, not written by us.

So even if it does have a return value, it’s hard to use it. If you really want to make up for both Runnable defects, you can use the following remedy: Callable.

Callable interface

Callable is an interface similar to Runnable. Classes that implement Callable and classes that implement Runnable are tasks that can be executed by other threads. Let’s take a look at the Callable source:

public interface Callable<V{

     call(a) throws Exception;

}
Copy the code

Throws Exception (” Runnable “); throws Exception (” Runnable “); throws Exception (” Runnable “); To implement the Callable interface, you implement the Call method, whose return value is generic V. If you put the result of the call into this object, you can use the call method’s return value to obtain the result of the child thread’s execution.

The difference between Callable and Runnable

To summarize the differences between Callable and Runnable:

  • Method name, Callable executes call() and Runnable executes run();
  • The Callable task returns a value, while the Runnable task does not return a value.
  • To throw an exception, the call() method can throw an exception, but the run() method cannot.
  • Callable has a Future class that can be used to check the execution status of a task, cancel the execution of a task, and obtain the results of the task execution. Runnable cannot do all these functions. Callable is more powerful than Runnable.

Choose different implementations according to different scenarios.