7 Callable接口
创建线程的多种方式:
- 继承Thread类
- 实现Runnable接口
- Callable接口
- 线程池
7.1 Callable接口创建线程
目前学习了有两种创建线程的方法,一种是通过创建 Thread 类,另一种是通过使用 Runnable 创建线程,但是,Runnable 缺少的一项功能是,当线程终止时(即 run()完成时),我们无法使线程返回结果。为了支持此功能,Java 中提供了 Callable 接口
比较Runnable接口和Callable接口
Callable中的call()计算结果,如果无法计算结果,会抛出异常
- Runnable中的run()使用实现接口Runnable的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用该对象的run方法
总的来说:run()没有返回值,不会抛出异常。而call()有返回值,会抛出异常
因为Thread的构造函数中没有Callable接口的参数设置,直接替换不可以,只能用下面这种线程创建方法(找一个类,即和Runnable接口有关系,又和Callable接口有关系)
发现Runnable接口有实现类FutureTask(中间对象)
FutureTask的构造函数有Callable参数,通过FutureTask创建线程对象
使用 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());
}
}
输出为:
Thread-0执行Runnable
Thread-1使用Callable接口
Callable返回值:Callable接口返回值
详细代码可以参考如下代码
//比较 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()); //调用里面的返回值
}
}
7.2 FutureTask
进入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()获取结果
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);
}
未来的任务,如果运行过一次,那么下一次,就直接得到结果