Callable 接口:
创建线程的多种方式:
- 继承Thread类
- 实现Runnable接口
- Callable接口
- 线程池
1.Callable接口创建线程:
目前学习了有两种创建线程的方法,一种是通过创建 Thread 类,另一种是通过使用 Runnable 创建线程,但是,Runnable 缺少的一项功能是,当线程终止时(即 run()完成时),我们无法使线程返回结果。为了支持此功能,Java 中提供了 Callable 接口:
比较Runnable接口和Callable接口:
- Callable中的call()计算结果,如果无法计算结果,会抛出异常。
- Runnable中的run()使用实现接口Runnable的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用该对象的run方法。
总的来说:run()没有返回值,不会抛出异常。而call()有返回值,会抛出异常
2.FutureTask 实现类:
因为Thread的构造函数中没有Callable接口的参数设置,直接替换不可以,只能用下面这种线程创建方法(找一个类,即和Runnable接口有关系,又和Callable接口有关系)
发现Runnable接口有实现类FutureTask(中间对象)未来任务
FutureTask的构造函数有Callable参数,通过FutureTask创建线程对象,java.util.concurrent.FutureTask<V>
https://www.matools.com/file/manual/jdk_api_1.8_google/java/util/concurrent/FutureTask.html
使用 lambda 方式创建代码如下:
public class CallableTest { public static void main(String[] args) throws ExecutionException, InterruptedException { new Thread(()->{ System.out.println(Thread.currentThread().getName()+"执行Runnable"); }).start(); FutureTask<String> task = new FutureTask<>(() -> { System.out.println(Thread.currentThread().getName() + "使用Callable接口"); return "Callable接口返回值"; }); new Thread(task).start(); System.out.println("Callable返回值:" + task.get()); } }
//比较 callable和runnable 的区别 class MyThread1 implements Runnable{ @Override public void run() { //这里没有返回值 } } class MyThread2 implements Callable{ @Override public Object call() throws Exception { System.out.println(Thread.currentThread().getName()+"线程运行"); return "Callable 的实现线程"; //有返回值 } } public class diffentence { public static void main(String[] args) throws ExecutionException, InterruptedException { //创建 实现Runnable 的线程 new Thread( new MyThread1(),"t1" ).start(); //创建 实现Callable 的线程 不能直接替换 ,没有这个类型的构造方法 // new Thread( new MyThread2(),"t2" ).start(); //选择FutureTask 他是 Runnable 的实现类,而且构造方法含有Callable类型 FutureTask<String> task = new FutureTask(new MyThread2()); new Thread(task,"hhh").start(); System.out.println("返回值"+task.get()); //调用里面的返回值 } }
源码解析:
进入FutureTask底层源码可以看到它的构造器:
// 创建一个FutureTask,一旦运行就执行给定的Callable public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable } // 创建一个FutureTask,一旦运行就执行给定的Ru你那边了,并安排成功完成时get返回给定的结果 public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable }
其他常用的代码:
// get()获取call方法计算完成的返回值结果: public V get() throws InterruptedException, ExecutionException { int s = state; if (s <= COMPLETING) s = awaitDone(false, 0L); return report(s); } // outcome就是返回值: private V report(int s) throws ExecutionException { Object x = outcome; if (s == NORMAL) return (V)x; if (s >= CANCELLED) throw new CancellationException(); throw new ExecutionException((Throwable)x); }
未来的任务,如果运行过一次,那么下一次,就直接得到结果!