面试题:java Runnable与Callable 的区别

相同点

  1. 都是接口;(废话,当然是接口了)
  2. 都可用来编写多线程程序;
  3. 都需要调用Thread.start()启动线程。
  4. Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。

不同点

  1. 实现Callable接口的任务线程能返回执行结果,而实现Runnable接口的任务线程不能返回结果,这是核心区别
    注意点:Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞!

  2. Callable接口的call()方法允许抛出异常,而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;

  3. 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());
       }
   }
}
posted @ 2022-04-03 17:02  楼兰胡杨  阅读(217)  评论(0编辑  收藏  举报