创建线程的两种方式:继承Thread类 或 实现Runnable接口,重写run方法。
Thread类本身也实现了Runnable接口,Runnable接口源码:
run方法是无返回值的,所以在JDK1.5出现了Callable接口
Callable接口源码
Callable是一个函数式接口(接口中仅有一个方法),也是一个泛型接口,返回值类型和泛型一致
Future接口源码
cancel:取消任务的执行,如果任务已完成或已被取消,则返回false
isCancelled:判断任务是否被取消
isDone:判断任务是否完成
get():阻塞获取任务的执行结果
get(long timeout, TimeUnit unit):在规定的时间内,阻塞获取任务的执行结果;如果在规定的时间内未获取到结果,则抛出TimeoutException
Future接口提供了取消任务,任务状态查询,任务结果获取的能力;
Future机制就是为了解决多线程返回值的问题;
RunnableFuture接口源码
RunnableFuture继承了Runnable和Future两个接口,也就同时具备其两个接口的功能
FutureTask是真正工作的处理类,实现了RunnableFuture接口,而RunnableFuture接口继承了Runnable和Future接口,所以FutureTask既可以作为Runnable被Thread执行,也可以获取Future异步执行的结果;
FutureTask两个构造方法,一个接收Callable的参数实例,另一个接收Runnable的参数实例
当传入的参数是Runnable时,通过Executors.callable(runnable, result)方法将其转成Callable类型,返回值类型为V(指定的泛型类型)
FutureTask代码示例
package com.example.demo.test; import java.util.concurrent.*; public class ThreadTest { private static ExecutorService pool = Executors.newFixedThreadPool(5); public static void main(String[] args) throws Exception { FutureTask<Integer> futureTask = new FutureTask<>(new MyTask()); // FutureTask实现了RunnableFuture接口,RunnableFuture接口继承了Runnable接口,因此可以作为Thread构造参数传入 new Thread(futureTask).start(); // 获取线程执行的结果,get()会阻塞当前线程 int result = futureTask.get(); System.out.println("result-1:" + result); // 线程池执行 pool.submit(futureTask); // 获取线程执行的结果,get()会阻塞当前线程 result = futureTask.get(); System.out.println("result-2:" + result); // 直接由线程池执行 Future<Integer> future = pool.submit(new MyTask()); // 获取线程执行的结果,get()会阻塞当前线程 result = future.get(); System.out.println("result-3:" + result); pool.shutdown(); } static class MyTask implements Callable<Integer> { @Override public Integer call() throws Exception { int sum = 0; for (int i = 0; i < 100; i++) { sum += i; } TimeUnit.SECONDS.sleep(1); return sum; } } }
Callable、Runnable,Future和FutureTask之间关系
原文:https://www.cnblogs.com/lwcode6/p/14803855.html