Callable接口与Runnable接口的区别:
- Runnable接口:
- 无返回值;
- 不抛出异常;
- Callable接口:
- 有返回值;
- 抛出异常;
使用Runnable接口作为参数创建线程可以直接传匿名内部类的Lambda表达式:
Thread thread = new Thread(()->{
//...
});
上述方法是因为Thread类支持了Runnable接口,而Callable需要作为线程来使用则需要一个中间人:
FutureTask类支持了使用Runnable或Callable来创建一个实例:
public class FutureTask<V> implements RunnableFuture<V> {
//...
public FutureTask(Callable<V> callable) {
//....
}
public FutureTask(Runnable runnable, V result) {
//...
}
//...
}
我们发现该类实现了一个RunnableFuture接口:
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
该接口继承了Runnable与Future,因此按Java的继承与多态的特性来看,FutureTask可以作为Thread构造方法的参数传入,从而创建线程:
//包装Runnable接口,手动传入返回值
FutureTask<Integer> futureTask1 = new FutureTask<>(new RunnableImpl(), 100);
//包装Callable接口,由callable接口的实现类调用call方法来返回值
FutureTask<Integer> futureTask2 = new FutureTask<>(new CallableImpl());
new Thread(futureTask1).start();
new Thread(futureTask2).start();
//调用FutureTask实例的get方法会等待线程运行完毕将结果返回
System.out.println(futureTask1.get());
System.out.println(futureTask2.get());