Java的Future接口
Java的Future接口
Java 中的 Future 接口和其实现类 FutureTask,代表了异步计算的结果。
1. Future接口简介
Future 是异步计算结果的容器接口,它提供了下面这些功能:
- 在等待异步计算完成时检查计算结果是否完成
- 在异步计算完成后获取计算结果
- 在异步计算完成前取消
Future 可以用于耗时的异步计算任务。例如我们把 Runnable 接口或 Callable 接口的实现类提交到线程池时,线程池会返回一个 FutureTask 对象。
<T> Future<T> submit(Callable<T> task)
<T> Future<T> submit(Runnable<T> task, T result)
下文会再解释 FutureTask,这是 Future 接口的一个实现类。
Future 接口提供了下面这些方法
| Modifier and Type | Method | Description |
|---|---|---|
boolean |
cancel(boolean mayInterruptIfRunning) |
尝试取消执行此任务。 |
V |
get() |
等待计算完成,然后检索其结果。 |
V |
get(long timeout, TimeUnit unit) |
如果需要等待最多在给定的时间计算完成,然后检索其结果(如果可用)。 |
boolean |
isCancelled() |
如果此任务在正常完成之前被取消,则返回 true 。 |
boolean |
isDone() |
返回 true如果任务已完成。 |
2. FutureTask的使用
可以将 FutureTask 交给 Executor 执行,也可以通过ExecutorService.submit(...)方法返回一个 FutureTask,然后执行 get 方法或 cancel 方法。
也可以单独使用 FutureTask,比如下面的代码就实现了一种需求:一个线程必须等待另一个线程把某个任务执行完后它才能继续执行。假设有多个线程执行若干个任务,每个任务最多只能同时被执行一次,多个线程试图执行同一个任务时,只允许一个线程执行任务,其他线程等待这个任务执行完后才能继续执行。
public class ConcurrentTask {
private final ConcurrentMap<Object, Future<String>> taskCache = new ConcurrentHashMap<Object, Future<String>>();
private String executionTask(final String taskName) throws ExecutionException, InterruptedException {
while (true) {
Future<String> future = taskCache.get(taskName); //1.1,2.1
if (future == null) {
// 创建 Task
Callable<String> task = new Callable<String>() {
public String call() throws InterruptedException {
//......
return taskName;
}
};
//1.2 创建 FutureTask
FutureTask<String> futureTask = new FutureTask<>(task);
future = taskCache.putIfAbsent(taskName, futureTask); //1.3
// 如果是第一次放入,则尝试执行
if (future == null) {
future = futureTask;
futureTask.run(); //1.4执行任务
}
}
try {
return future.get(); //1.5,2.2线程在此等待任务执行完成
} catch (CancellationException e) {
taskCache.remove(taskName, future);
}
}
}
}
相信不难理解,下面是执行的示意图。

3. FutureTask的实现
FutureTask 的实现基于队列同步器 QAS。
基于复合优先于继承的原则,FutureTask 声明了一个内部私有的,继承于 AQS 的子类 Sync,这对 FutureTask 所有公有方法的调用都会委托给这个内部子类。

FutureTask 的get方法会调用AQS.acquireSharedInterruptibly(int arg)方法,执行过程如下:
- 调用
AQS.acquireSharedInterruptibly(int arg)方法,首先回调子类 Sync 中的方法tryAcqurieShared判断acquire操作是否可以成功。acquire操作成功的条件为:state 为执行完成状态 RAN 或已取消状态 CANCELLED 且 runner 不为 null。 - 如果成功则
get方法立即返回,失败则到线程等待队列中去等待其他线程执行release。 - 当其他线程执行
release,如FutureTask.run()和FutureTask.cancel(),唤醒当前线程后。当前线程再次执行tryAcquireShared将返回值 1,当前线程离开等待队列并唤醒后续线程。 - 最后返回结果或抛出异常。
FutureTask 的 run 方法执行过程如下:
- 执行构造函数中指定的任务。
- 原子方式更新同步状态,调用
AQS.compareAndSetState - 如果上面的原子操作成功,设置代表计算结果的变量 result 的值为
Callable.call()的返回指,然后调用AQS.releaseShared(int arg) AQS.releaseShared(int arg)首先回调 Sync 中的tryReleaseShared(arg)来执行release。这个方法唤醒等待队列中第一个线程。- 调用
FutureTask.done()。
当调用FutureTask.get()方法时,如果 FutureTask 不是处于执行完成状态 RAN 或已取消状态 CANCELLED。当前执行线程将到 AQS 的线程等待队列中等待。

Java的Future接口的更多相关文章
- java Future 接口介绍
(转自:http://blog.csdn.net/yangyan19870319/article/details/6093481) 在Java中,如果需要设定代码执行的最长时间,即超时,可以用Java ...
- Java基础知识强化之网络编程笔记25:Android网络通信之 Future接口介绍(Java程序执行超时)
1. Future接口简介 在Java中,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现. Future接口是Java标准API ...
- Java并发编程:Future接口、FutureTask类
在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需要获取执行结果,就 ...
- 浅谈Java Future接口
Java项目编程中,为了充分利用计算机CPU资源,一般开启多个线程来执行异步任务.但不管是继承Thread类还是实现Runnable接口,都无法获取任务执行的结果.JDK 5中引入了Callable和 ...
- Java Callable接口、Runable接口、Future接口
1. Callable与Runable区别 Java从发布的第一个版本开始就可以很方便地编写多线程的应用程序,并在设计中引入异步处理.Thread类.Runnable接口和Java内存管理模型使得多线 ...
- Java程序执行超时——Future接口介绍
在Java中,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现. Future接口是Java标准API的一部分,在java.uti ...
- Callable接口、Runable接口、Future接口
1. Callable与Runable区别 Java从发布的第一个版本开始就可以很方便地编写多线程的应用程序,并在设计中引入异步处理.Thread类.Runnable接口和Java内存管理模型使得多线 ...
- Java 多线程Future和FutureTask
Future表示一个任务的周期,并提供了相应的方法来判断是否已经完成或者取消,以及获取任务的结果和取消任务. Future接口源码: public interface Future<V> ...
- 彻底理解Java的Future模式
先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...
随机推荐
- No shutdown animation in the electricity display only 1%
低电量自动关机时无关机动画 低电量自动关机时无关机动画1. 问题描述2. 分析3. solution4. 总结 1. 问题描述 DEFECT DESCRIPTION: No shutdown anim ...
- 【Java】Java8新特性
文章目录 Java8新特性 Lambda表达式的使用 语法格式一:无参,无返回值 语法格式二:Lambda 需要一个参数,但是没有返回值. 语法格式三:数据类型可以省略,因为可由编译器推断得出,称为& ...
- 【Java】多态性
文章目录 多态性 向下转型 多态性 可以理解为一个事物的多种形态. 对象的多态性:父类的引用指向子类的对象.只适用于方法,不适用于属性(编译和运行都看左边) 总结:对于对象的多态性,编译,看左边:运行 ...
- 【摘抄】疑问chatterbot
ChatterBot使用哪种机器学习? -------------------------------------------------- - 简而言之,ChatterBot使用了许多不同的机器学 ...
- 2022GDUT寒训专题一I题
题目 题面 给一个长度为 N的数组,一个长为 K的滑动窗体从最左端移至最右端,你只能看到窗口中的 K 个数,每次窗体向右移动一位,如下图: 窗口位置 最小值 最大值 [1 3 -1] -3 5 3 6 ...
- Gc如何判断对象可以被回收?
Gc如何判断对象可以被回收? 1 引用计数器 引用计数法的算法思路:给对象增加一个引用计数器,每当对象增加一个引用计数器+1,失去一个引用-1,所以当计数器是0的时候对象就没有引用了,就会被认为可回收 ...
- strace -cp 诊断
strace -c php do.php 各项含义如下: - % time:执行耗时占总时间百分比 - seconds:执行总时间 - usecs/call:单个命令执行时间 - calls:调用次数 ...
- 在js中如何区分深拷贝与浅拷贝?
一.自我理解 简单来讲就是:深拷贝层层拷贝,浅拷贝只拷贝第一层. 在深拷贝中,新对象中的更改不会影响原对象,而在浅拷贝中,新对象中的更改,原对象中也会跟着改. 在深拷贝中,原对象与新对象不共享相同的属 ...
- Linux 配置 kibana
一.Kibana 是啥? Kibana是一个针对Elasticsearch的开源分析及可视化平台,用来搜索.查看交互存储在Elasticsearch索引中的数据. 二.安装步骤? 1.kibana 是 ...
- Lesson2——NumPy Ndarray 对象
NumPy 教程目录 NumPy Ndarray 对象 NumPy 最重要的一个特点是其 $N$ 维数组对象 ndarray,它是一系列同类型数据的集合,以 $0$ 下标为开始进行集合中元素的索引. ...