callable和future和runnable

1.call方法可以有返回值;
2.call方法可以声明抛出异常。
因此我们完全可以提供一个Callable对象作为Thread的target,而该线程的线程执行体就是该Callable对象的call方法,问题是:Callable接口是java5新增的接口,而且它并没有继承Runnable接口,所以Callable接口不可以直接作为Thread的target,而且call方法还有一个返回值,那么我们如何获取call方法的返回值呢?java5提供了Future接口代表Callable接口里call方法的返回值,FutureTask是Future的实现类,FutureTask实现了Runnable接口,所以创建线程时,可以将FutureTask传入,另外,FutureTask创建时需要一个Callable参数,所以这样一来,Callable就和Thread挂钩了,Thread实际执行的是Callable的call方法,而其返回值由FutureTask获取,调用其get方法即可获得返回值。

示例代码:

[java]  view plain  copy
  1. Callable<Integer> c = new Callable<Integer>()  
  2.         {  
  3.             @Override  
  4.             public Integer call() throws Exception  
  5.             {  
  6.                 System.out.println("running...");  
  7.                 Thread.sleep(2000);  
  8.                 return 215;  
  9.             }  
  10.         };  
  11.         FutureTask<Integer> task = new FutureTask<>(c);  
  12.         new Thread(task).start();  
  13.         try  
  14.         {  
  15.             System.out.println("result  : "+task.get());  
  16.         }  
  17.         catch (InterruptedException e)  
  18.         {  
  19.             e.printStackTrace();  
  20.         }  
  21.         catch (ExecutionException e)  
  22.         {  
  23.             e.printStackTrace();  
  24.         }  
  25.     }  

上面说到可以调用FutureTask方法获取call的返回值,那么如果call方法是个耗时操作,调用get方法的线程岂不是得一直等着call结束么?恩,确实是这样。 调用get方法的线程会阻塞

下面从源码角度简单分析下Callable和Future:
Callable方法没啥好说的, 只有一个call方法,作为线程的执行体
[java]  view plain  copy
  1. public interface Callable<V> {  
  2.     V call() throws Exception;  
  3. }  

FutureTask类实现了RunnableFuture接口,而RunnableFuture继承了Runnable和Future接口:


Runnable接口大家都很熟悉,那么这个Future接口提供了什么样的方法呢?

[java]  view plain  copy
  1. public interface Future<V> {  
  2.     boolean cancel(boolean mayInterruptIfRunning);//取消Future里面关联的call方法  
  3.     boolean isCancelled();//任务是否取消  
  4.     boolean isDone();//任务是否完成  
  5.     V get() throws InterruptedException, ExecutionException;//获取call方法的结果  
  6.     V get(long timeout, TimeUnit unit)//设置超时时间,超过此时间未收到结果将抛出异常  
  7.         throws InterruptedException, ExecutionException, TimeoutException;  
  8. }  

我们都知道,当Thread被start之后,会调用Thread的run方法,而Thread的run方法逻辑如下:
[java]  view plain  copy
  1. @Override  
  2.    public void run() {  
  3.        if (target != null) {  
  4.            target.run();  
  5.        }  
  6.    }  
即判断是否传入了Runnable类型的target,如果有,将会执行Runnable的run方法,这里我们传入的是FutureTask,所以会调用FutureTask类的run方法:
[java]  view plain  copy
  1. public void run() {  
  2.       sync.innerRun();  
  3.   }  

只有一行代码,调用了sync类的innerRun方法,sync为FutureTask的内部类,我们继续追踪此方法的实现:
[java]  view plain  copy
  1. void innerRun() {  
  2.             if (!compareAndSetState(READY, RUNNING))  
  3.                 return;  
  4.             runner = Thread.currentThread();  
  5.             if (getState() == RUNNING) { // recheck after setting thread  
  6.                 V result;  
  7.                 try {  
  8.                     result = callable.call();//调用的是callable的call方法  
  9.                 } catch (Throwable ex) {  
  10.                     setException(ex);  
  11.                     return;  
  12.                 }  
  13.                 set(result);  
  14.             } else {  
  15.                 releaseShared(0); // cancel  
  16.             }  
  17.         }  

innerRun方法中果然还是调用了callable的call方法,并将结果赋给result变量
再看FutureTask的get方法:
[java]  view plain  copy
  1. public V get() throws InterruptedException, ExecutionException {  
  2.         return sync.innerGet();  
  3.     }  

调用的是sync的innerGet方法:
[java]  view plain  copy
  1. V innerGet() throws InterruptedException, ExecutionException {  
  2.            acquireSharedInterruptibly(0);  
  3.            if (getState() == CANCELLED)  
  4.                throw new CancellationException();  
  5.            if (exception != null)  
  6.                throw new ExecutionException(exception);  
  7.            return result;  
  8.        }  
返回了result变量。

此外线程池ExecutorService executor = Executors.newFixedThreadPool(threads);提供了方法invokeAll(List<callable<object>)来执行所有线程。返回结果为list<future<object>>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值