Callable接口是另一种获得线程的方法,在这之前,所知道的获得线程的方法是:继承Thread类,实现Runnable接口。
在这里需要知道runnable接口和callable接口的区别
- Callable有返回值,runnable没有返回值
- Callable抛异常,runnable不抛异常
- 落地方法不一样,一个是run,一个是call
class mythread1 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
}
}
class myThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
return null;
}
}
这里需要知道实现Callable接口的返回值是和它的泛型一致的。
实现这个接口简单,但是想要启动这个线程的时候,就不好办了,因为Thread类的构造方法可以传Runnable接口,但是不可以传Callable接口,那么该怎么办呢?
我们在Runnable子接口中找到了一个RunnableFuture,有一个类FutureTask实现了RunnableFuture接口。这个FutureTask类的构造方法还需要传一个Callable接口。
这样就找到了一个类同时和Callable和Runnable挂上钩。
在给Thread类传递Runnable接口时,利用多态,向里面传递了一个Runnable接口的子接口的实现类。
知道了这个接口,怎么去理解Callable接口呢
用一个图来展示
最后还有一个需要注意的地方,当用两个不同的线程,去调用同一个FutureTask对象,实现Callable的类都只执行一遍。
class myThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("come in here");
// 暂停一会线程
TimeUnit.SECONDS.sleep(4);
return 1024;
}
}
public class CallableDemo {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//一个FutureTask不管几个线程去调用,调用的都是同一个FutureTask对象,只会调用一次。就好像已经算出来的结果,再去让别人算同一个题,他会直接告诉你结果
FutureTask<Integer> futureTask = new FutureTask<>(new myThread());
new Thread(futureTask,"a").start();
new Thread(futureTask,"b").start();
System.out.println(Thread.currentThread().getName()+"计算完成");
// get方法一般请放在最后一行
System.out.println(futureTask.get());
}
}