The relationship between Callable, Runnable, Future and FutureTask

There are two ways to create a thread: inherit the Thread class or implement the Runnable interface and override the run method.

The Thread class itself also implements the Runnable interface. Runnable interface source code:

The run method has no return value, so the Callable interface appeared in JDK1.5

Relationship class diagram

Callable

Callable interface source code

Callable is a functional interface (there is only one method in the interface), and it is also a generic interface. The return value type is the same as that of generics.

Future

Future interface source code

cancel: Cancel the execution of the task, return false if the task has been completed or canceled

isCancelled: Determine whether the task has been canceled

isDone: Determine whether the task is completed

get(): blocking to obtain the execution result of the task

get(long timeout, TimeUnit unit): blocks to obtain the execution results of the task within the specified time

The Future interface provides the ability to cancel tasks, query task status, and obtain task results;

The Future mechanism is to solve the problem of multi-thread return values;

RunnableFuture

RunnableFuture interface source code

RunnableFuture inherits the two interfaces Runnable and Future, and has the functions of both interfaces at the same time.

FutureTask

FutureTask is a real work processing class that implements the RunnableFuture interface, and the RunnableFuture interface inherits the Runnable and Future interfaces, so FutureTask can be executed by Thread as a Runnable, and can also obtain the results of asynchronous execution of Future;

FutureTask has two constructors, one receiving a Callable parameter instance and the other receiving a Runnable parameter instance.

When the incoming parameter is a Runnable, it is converted into a Callable type through the Executors.callable(runnable, result) method (eventually all tasks of the Callable type are executed), and the return value type is V (the specified generic type)

RunnableAdapterAdapter

FutureTask-demo example

In the ExecutorService thread pool interface, the sumbit method defines the Runnable input parameter type and the Callable input parameter type.

package com.example.demo.test;

import java.util.concurrent.*;

public class RunnableFutureTest {

    private static ExecutorService pool = Executors.newFixedThreadPool(2);

    public static void main(String[] args) throws Exception {
        testFuture(20);
        testRunnable(20);
    }

    /**
     * new Thread().start() creates a new thread and starts the thread (actually executes the run method, no return value)
     */
    static void testRunnable(int number) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("runnable sum:" + calcOneToTargetSum(number));
            }
        }).start();
    }

    /**
     * Runnable: implements run(), has no return value, and cannot throw exceptions
     * Callable: implements call(), has a return value, and can throw exceptions
     * Runnable can be directly handed over to Thread for execution
     * Callable cannot be directly handed over to Thread for execution, but is generally handed over to ExecutorService for execution.
     */
    static void testFuture(int number) {
        try {
            Future<?> result1 = pool.submit(new Runnable() {
                @Override
                public void run() {
                    calcOneToTargetSum(number);
                }
            });
            // No return value, get() will block
            System.out.println("result1:" + result1.get());

            Future<Integer> result2 = pool.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    return calcOneToTargetSum(number);
                }
            });
            // If there is a return value, get() will block
            System.out.println("result2:" + result2.get());

            FutureTask<Integer> futureTask1 = new FutureTask<>(new Runnable() {
                @Override
                public void run() {
                    calcOneToTargetSum(number);
                }
            }, calcOneToTargetSum(number));
            pool.submit(futureTask1);
            // If there is a return value, get() will block
            System.out.println("result3:" + futureTask1.get());

            FutureTask<Integer> futureTask2 = new FutureTask<>(new Runnable() {
                @Override
                public void run() {
                    calcOneToTargetSum(number);
                }
            }, calcOneToTargetSum(number));
            pool.submit(futureTask2);
            // Executors.callable will convert Runnable to Callable, inherent return value, get() will block
            System.out.println("result4:" + futureTask2.get());
            <br>// FutureTask implements the RunnableFuture interface. The RunnableFuture interface inherits the Runnable interface, so it can be passed in as a Thread construction parameter.
            new Thread(futureTask2).start();
            // No return value, get() will block
            System.out.println("result5:" + futureTask2.get());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
          pool.shutdown();
        }
    }

    static int calcOneToTargetSum(int number) {
        int sum = 0;
        for (int i = 0; i < number; i + + ) {
            sum + = i;
        }
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return sum;
    }

}

The difference between Runnable and Callable interfaces:

  • The method defined by Runnable is run(), and the method defined by Callable is call()
  • The method defined by Runnable is run() without a return value, while the method defined by Callable is call() with a return value.
  • The method defined by Runnable is run() and cannot throw an exception, while the method defined by Callable is call() which can throw an exception.