概要

本章介绍线程池中的Callable和Future。
Callable 和 Future 简介
示例和源码分析(基于JDK1.7.0_40)

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3544116.html

Callable 和 Future 简介

  Callable 和 Future 是比较有趣的一对组合。当我们需要获取线程的执行结果时,就需要用到它们。Callable用于产生结果,Future用于获取结果。

1. Callable

Callable 是一个接口,它只包含一个call()方法。Callable是一个返回结果并且可能抛出异常的任务。

为了便于理解,我们可以将Callable比作一个Runnable接口,而Callable的call()方法则类似于Runnable的run()方法。

Callable的源码如下:

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

说明:从中我们可以看出Callable支持泛型。

2. Future

Future 是一个接口。它用于表示异步计算的结果。提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。

Future的源码如下:

public interface Future<V> {
// 试图取消对此任务的执行。
boolean cancel(boolean mayInterruptIfRunning) // 如果在任务正常完成前将其取消,则返回 true。
boolean isCancelled() // 如果任务已完成,则返回 true。
boolean isDone() // 如有必要,等待计算完成,然后获取其结果。
V get() throws InterruptedException, ExecutionException; // 如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}

说明: Future用于表示异步计算的结果。它的实现类是FutureTask,在讲解FutureTask之前,我们先看看Callable, Future, FutureTask它们之间的关系图,如下:

说明
(01) RunnableFuture是一个接口,它继承了Runnable和Future这两个接口。RunnableFuture的源码如下:

public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}

(02) FutureTask实现了RunnableFuture接口。所以,我们也说它实现了Future接口。

示例和源码分析(基于JDK1.7.0_40)

我们先通过一个示例看看Callable和Future的基本用法,然后再分析示例的实现原理。

 import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ExecutionException; class MyCallable implements Callable { @Override
public Integer call() throws Exception {
int sum = 0;
// 执行任务
for (int i=0; i<100; i++)
sum += i;
//return sum;
return Integer.valueOf(sum);
}
} public class CallableTest1 { public static void main(String[] args)
throws ExecutionException, InterruptedException{
//创建一个线程池
ExecutorService pool = Executors.newSingleThreadExecutor();
//创建有返回值的任务
Callable c1 = new MyCallable();
//执行任务并获取Future对象
Future f1 = pool.submit(c1);
// 输出结果
System.out.println(f1.get());
//关闭线程池
pool.shutdown();
}
}

运行结果

4950

结果说明
  在主线程main中,通过newSingleThreadExecutor()新建一个线程池。接着创建Callable对象c1,然后再通过pool.submit(c1)将c1提交到线程池中进行处理,并且将返回的结果保存到Future对象f1中。然后,我们通过f1.get()获取Callable中保存的结果;最后通过pool.shutdown()关闭线程池。

1. submit()

submit()在java/util/concurrent/AbstractExecutorService.java中实现,它的源码如下:

public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
// 创建一个RunnableFuture对象
RunnableFuture<T> ftask = newTaskFor(task);
// 执行“任务ftask”
execute(ftask);
// 返回“ftask”
return ftask;
}

说明:submit()通过newTaskFor(task)创建了RunnableFuture对象ftask。它的源码如下:

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}

2. FutureTask的构造函数

FutureTask的构造函数如下:

public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
// callable是一个Callable对象
this.callable = callable;
// state记录FutureTask的状态
this.state = NEW; // ensure visibility of callable
}

3. FutureTask的run()方法

我们继续回到submit()的源码中。
在newTaskFor()新建一个ftask对象之后,会通过execute(ftask)执行该任务。此时ftask被当作一个Runnable对象进行执行,最终会调用到它的run()方法;ftask的run()方法在java/util/concurrent/FutureTask.java中实现,源码如下:

public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
// 将callable对象赋值给c。
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// 执行Callable的call()方法,并保存结果到result中。
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
// 如果运行成功,则将result保存
if (ran)
set(result);
}
} finally {
runner = null;
// 设置“state状态标记”
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}

说明:run()中会执行Callable对象的call()方法,并且最终将结果保存到result中,并通过set(result)将result保存。
      之后调用FutureTask的get()方法,返回的就是通过set(result)保存的值。


更多内容

1. Java多线程系列--“JUC线程池”02之 线程池原理(一)

2. Java多线程系列--“JUC线程池”03之 线程池原理(二)

3. Java多线程系列--“JUC线程池”04之 线程池原理(三)

4. Java多线程系列--“JUC线程池”05之 线程池原理(四)

5. Java多线程系列--“JUC线程池”01之 线程池架构

6. Java多线程系列目录(共xx篇)

Java多线程系列--“JUC线程池”06之 Callable和Future的更多相关文章

  1. Java多线程系列 JUC线程池06 线程池原理解析(五)

    ScheduledThreadPoolExecutor解析 ScheduledThreadPoolExecutor适用于延时执行,或者周期性执行的任务调度,ScheduledThreadPoolExe ...

  2. Java多线程系列--“JUC线程池”02之 线程池原理(一)

    概要 在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析Th ...

  3. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  4. Java多线程系列--“JUC线程池”04之 线程池原理(三)

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--“基础篇”01之 基 ...

  5. Java多线程系列--“JUC线程池”05之 线程池原理(四)

    概要 本章介绍线程池的拒绝策略.内容包括:拒绝策略介绍拒绝策略对比和示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3512947.html 拒绝策略 ...

  6. Java多线程系列--“JUC线程池”01之 线程池架构

    概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介绍JUC的最后一部分的内容——线程池.内容包括:线程池架构 ...

  7. Java多线程系列 JUC线程池04 线程池原理解析(三)

    转载 http://www.cnblogs.com/skywang12345/p/3509954.html  https://blog.csdn.net/qq_22929803/article/det ...

  8. Java多线程系列 JUC线程池05 线程池原理解析(四)

    转载 http://www.cnblogs.com/skywang12345/p/3544116.html  https://blog.csdn.net/programmer_at/article/d ...

  9. Java多线程系列 JUC线程池03 线程池原理解析(二)

    转载  http://www.cnblogs.com/skywang12345/p/3509954.html  http://www.cnblogs.com/skywang12345/p/351294 ...

随机推荐

  1. spring入门(七)【springMVC返回json串】

    现在多数的应用为了提高交互性多使用异步刷新,即在不刷新整个页面的情况下,只刷新局部,局部刷新用得最多就是ajax,ajax和后台进行交互的数据格式使用的最多的是JSON,这里简单描述,在springm ...

  2. B/S结构的流程简单概述

    在介绍appl ication 对象之前,先简单介绍一些Web 服务器的实现原理.         对于大部分浏览器而言,它通常负责完成三件事情: (1)向远程服务器发送请求. (2)读取远程服务器返 ...

  3. jQuery元宵猜灯谜特效(元宵十五日猜一个字)

    在线体验:http://keleyi.com/keleyi/phtml/jqtexiao/35.htm jQuery元宵猜灯谜特效的HTML代码如下: <!DOCTYPE html> &l ...

  4. CSS3中flexbox如何实现水平垂直居中和三列等高布局

    最近这些天都在弥补css以及css3的基础知识,在打开网页的时候,发现了火狐默认首页上有这样一个东西.

  5. angularjs+微信,解决chooseImage不能预览的问题

    在wx.chooseImage的success回调中直接进行数据绑定,却在ng-repeat时发现ng-src不加载微信localId的问题,类似wxLocalResource://imageid98 ...

  6. React-Native性能优化点

    shouldComponentUpdate 确保组件在渲染之后不需要再更新的,即静态组件,尽量在其中增加shouldComponentUpdate方法,防止二次消耗所产生的性能消耗 shouldCom ...

  7. ArcGIS API for Silverlight 使用GeometryService求解线与线的交点

    ///画线 void btn_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Button btn = sender as B ...

  8. 为阿里云站点部署免费 HTTPS

    本文记录了部署在阿里云的站点,在申请了免费的 SSL 证书后如何正确的部署到站点上,让站点支持 HTTPS 访问. 阿里云引入了沃通作为 CA 证书供应商,并开放了免费 SSL 申请的页面,之前一直想 ...

  9. 使用NuGet助您玩转代码生成数据————Entity Framework 之 Code First

    [前言] 如果是Code First老鸟或者对Entity Framework不感兴趣,就不用浪费时间往下看了. 记得09年第一次接触ORM————Linq2Sql,从此对她的爱便一发不可收拾,一年后 ...

  10. Mac使用极简教程

    最近领导让我写一篇关于Mac的使用教程,因为使用人群未知,所以尽量写的通俗易懂,可谓是关于Mac电脑使用的精简教程吧,在此发表出来以供参考. Mac因为安全性而闻名,我们拥有了一部Mac,那么我们来了 ...