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.