Runnable与Callable

Callable接口:

1 public interface Callable<V> {
2     V call() throws Exception;
3 }

Runnable接口:

1 public interface Runnable {
2     public abstract void run();
3 }

相同点:

  1. 两者都是接口;(废话)
  2. 两者都可用来编写多线程程序;
  3. 两者都需要调用Thread.start()启动线程;

 

不同点:

  1. 两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
  2. Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;

 

注意点:

  • Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞!

 

Callable工作的Demo:

 1 package com.callable.runnable;
 2 
 3 import java.util.concurrent.Callable;
 4 import java.util.concurrent.ExecutionException;
 5 import java.util.concurrent.FutureTask;
 6 
 7 /**
 8  * Created on 2016/5/18.
 9  */
10 public class CallableImpl implements Callable<String> {
11 
12     public CallableImpl(String acceptStr) {
13         this.acceptStr = acceptStr;
14     }
15 
16     private String acceptStr;
17 
18     @Override
19     public String call() throws Exception {
20         // 任务阻塞 1 秒
21         Thread.sleep(1000);
22         return this.acceptStr + " append some chars and return it!";
23     }
24 
25 
26     public static void main(String[] args) throws ExecutionException, InterruptedException {
27         Callable<String> callable = new CallableImpl("my callable test!");
28         FutureTask<String> task = new FutureTask<>(callable);
29         long beginTime = System.currentTimeMillis();
30         // 创建线程
31         new Thread(task).start();
32         // 调用get()阻塞主线程,反之,线程不会阻塞
33         String result = task.get();
34         long endTime = System.currentTimeMillis();
35         System.out.println("hello : " + result);
36         System.out.println("cast : " + (endTime - beginTime) / 1000 + " second!");
37     }
38 }

测试结果:

1 hello : my callable test! append some chars and return it!
2 cast : 1 second!
3 
4 Process finished with exit code 0

Runnable工作的Demo:

 1 package com.callable.runnable;
 2 
 3 /**
 4  * Created on 2016/5/18.
 5  */
 6 public class RunnableImpl implements Runnable {
 7 
 8     public RunnableImpl(String acceptStr) {
 9         this.acceptStr = acceptStr;
10     }
11 
12     private String acceptStr;
13 
14     @Override
15     public void run() {
16         try {
17             // 线程阻塞 1 秒,此时有异常产生,只能在方法内部消化,无法上抛
18             Thread.sleep(1000);
19         } catch (InterruptedException e) {
20             e.printStackTrace();
21         }
22         // 最终处理结果无法返回
23         System.out.println("hello : " + this.acceptStr);
24     }
25 
26 
27     public static void main(String[] args) {
28         Runnable runnable = new RunnableImpl("my runable test!");
29         long beginTime = System.currentTimeMillis();
30         new Thread(runnable).start();
31         long endTime = System.currentTimeMillis();
32         System.out.println("cast : " + (endTime - beginTime) / 1000 + " second!");
33     }
34 }

测试结果:

1 cast : 0 second!
2 hello : my runable test!
3 
4 Process finished with exit code 0

写此篇的原因是一次面试中问到Callable与Runnable的区别,当时用的多的是Runnable,而Callable使用很少!

比较了两者后(网上查了不少),发现Callable在很多特殊的场景下还是很有用的!最后留点抄的代码,加深对Callable的认识!

 1 package com.inte.fork;
 2 
 3 /**
 4  * Created on 2016/4/20.
 5  */
 6 
 7 import java.util.*;
 8 import java.util.concurrent.*;
 9 
10 import static java.util.Arrays.asList;
11 
12 public class Sums {
13 
14     static class Sum implements Callable<Long> {
15         private final long from;
16         private final long to;
17 
18         Sum(long from, long to) {
19             this.from = from;
20             this.to = to;
21         }
22 
23         @Override
24         public Long call() {
25             long acc = 0;
26             for (long i = from; i <= to; i++) {
27                 acc = acc + i;
28             }
29             System.out.println(Thread.currentThread().getName() + " : " + acc);
30             return acc;
31         }
32     }
33 
34     public static void main(String[] args) throws Exception {
35         ExecutorService executor = Executors.newFixedThreadPool(3);
36         List<Future<Long>> results = executor.invokeAll(asList(
37                 new Sum(0, 10), new Sum(0, 1_000), new Sum(0, 1_000_000)
38         ));
39         executor.shutdown();
40 
41         for (Future<Long> result : results) {
42             System.out.println(result.get());
43         }
44     }
45 }

 

posted @ 2018-08-21 13:38  浅滩沙洲  阅读(161)  评论(0编辑  收藏  举报