一、Callable是什么
它是一个接口,位于juc包下,代表一个异步的任务,在多线程环境下,使用callable更明智,因为有些时候,我们也许需要获取方法的执行结果,或者得到异常信息,那么使用callable接口要比使用runnable接口来的方便的多。
callable接口里面最重要的一个方法是call()方法,它能够自定义返回值类型,也可以抛出异常,以便程序员看到发生了什么错误。
那下面来看下如何使用callable接口吧。
二、使用步骤
1.自定义类实现callable接口
//范型的意思是作用于方法的返回值。
class MyThread implements Callable<Integer> {
@Override
public Integer call() {
System.out.println("call()"); // 会打印几个call
// 耗时的操作
return 1024;
}
}
2.测试
package com.lhh.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CalableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// new Thread(new Runnable()).start();
// new Thread(new FutureTask<V>()).start();
// new Thread(new FutureTask<V>( Callable )).start();
new Thread().start(); // 怎么启动Callable
MyThread thread = new MyThread();
FutureTask futureTask = new FutureTask(thread); // 适配类,可以把它理解为中间商,通过它来联系runnable,因为Thread构造接受的参数为runnable接口。
new Thread(futureTask,"A").start();
new Thread(futureTask,"B").start(); // 结果会被缓存,效率高
//这个get 方法可能会产生阻塞!把他放到最后,假如任务里面是一个非常耗时的操作,那么要等到这个耗时的操作执行完毕之后才能拿到结果。
Integer o = (Integer) futureTask.get();
System.out.println(o);
}
}
执行结果如下:
咦,很奇怪,我明明开启了两条线程执行任务的呀,怎么突然变成只能看到一个线程的执行结果呢?
这里其实是一个小细节,因为这里面是有缓存的,第一次的执行结果会被缓存起来,等你下次在执行相类似的操作的时候,直接从缓存里面拿就可以了,也就是不再执行call()方法了。
三、总结
callable的讲解到此结束,主要记住它的作用是用来处理多线程下的任务执行的,跟runnable的作用相同,但是它有它的优势
- 方法有返回值
- 方法可以抛出异常
runnable使用run方法执行任务,callable使用call()方法执行任务
记住在使用callable的过程当中,需要借助"中间商"FutureTask来连接。