伙伴们,又见面了,我们接着聊java多线程实现方式,上篇我们介绍了可以通过实现Runnable接口来实现多线程,但是会发现实现Runnable接口的方式执行run方法之后没有返回值,如果我们想获取执行之后的返回值呢,那么我们可以通过今天介绍的实现Callable接口的方法。首先看下Callable接口的源码:
@FunctionalInterface
public interface Callable<V> {
/**
* V为返回值类型
*/
V call() throws Exception;
}
通过@FunctionalInterface可以看出它是一个函数式接口,接收一个泛型作为返回值类型。对比下Runnable接口的源码:
@FunctionalInterface
public interface Runnable {
//没有返回值
public abstract void run();
}
可以发现Callable接口中call方法不仅可以有返回值还可以抛出异常,而Runnable接口中run方法没有返回值并且不能往外抛出异常。举个Callable接口的栗子:
/**
* 实现Callable接口
*/
public class CallableTest implements Callable<String> {
@Override
public String call() throws Exception {
//返回线程名
return Thread.currentThread().getName();
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
CallableTest callableTest = new CallableTest();
FutureTask<String> futureTask = new FutureTask(callableTest);
new Thread(futureTask,"callTest").start();
System.out.println(futureTask.get());
}
}
栗子中我们传递了String类型作为call方法的返回值,接下来我们看看main方法中的写法。
首先看下FutureTask的源码:
public class FutureTask<V> implements RunnableFuture<V>{
//其中一个构造方法
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
......
}
从中我们可以通过实现Callable接口的对象来创建FutureTask对象,FutureTask<V> 实现了 RunnableFuture<V>接口,接着分析下 RunnableFuture接口:
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
可见它继承了Runnable和Future<V>两个接口,那么就相当于FutureTask<V> 间接实现了Runnable接口。最后看下Thread的构造方法:
//可以给线程设置名称的构造方法
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
总结一下:在Thread类中有Runnable接口类型参数的构造方法,在上面的栗子中FutureTask<String>实现了 RunnableFuture<V> 接口,而 RunnableFuture<V> 接口又继承了Runnable接口和 Funture<V>接口,因此咱们可以将futureTask 当做是一个Runnable接口的实例(间接实现)传入Thread构造方法来创建并启动我们新建的线程,可以发现最终都是通过Thread对象调用start方法来获取CPU时间片从而执行线程,伙伴们 是这样不 咱们下期见!