面试题:java Runnable与Callable 的区别
相同点
- 都是接口;(废话,当然是接口了)
- 都可用来编写多线程程序;
- 都需要调用Thread.start()启动线程。
- Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。
不同点
-
实现Callable接口的任务线程能返回执行结果,而实现Runnable接口的任务线程不能返回结果,这是核心区别;
注意点:Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞! -
Callable接口的call()方法允许抛出异常,而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;
-
Runnable可以作为Thread构造器的参数,通过开启新的线程来执行,也可以通过线程池来执行。而Callable只能通过线程池执行。
Callable实战
下面是Callable的应用场景,用于求和并打印计算结果。
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class SumCallableImpl implements Callable<Long> {
private final long from;
private final long to;
SumCallableImpl(long from, long to) {
this.from = from;
this.to = to;
}
@Override
public Long call() {
long acc = 0;
for (long i = from; i <= to; i++) {
acc = acc + i;
}
System.out.println(Thread.currentThread().getName() + " : " + acc);
return acc;
}
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Future<Long>> results = executor.invokeAll(Arrays.asList(
new SumCallableImpl(0, 10), new SumCallableImpl(0, 1_000), new SumCallableImpl(0, 1_000_000)
));
executor.shutdown();
System.out.println("打印执行结果:");
for (Future<Long> result : results) {
System.out.println(result.get());
}
}
}
读后有收获,小礼物走一走,请作者喝咖啡。
Buy me a coffee. ☕Get red packets.
作者:楼兰胡杨
本文版权归作者和博客园共有,欢迎转载,但请注明原文链接,并保留此段声明,否则保留追究法律责任的权利。