Future、Callable 、FutureTask详解
1.Future和Callable
Future是一个接口表示异步计算的结果,它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。Future提供了get()、cancel()、isCancel()、isDone()四种方法,表示Future有三种功能:
1、判断任务是否完成
2、中断任务
3、获取任务执行结果
Callable和Runnable差不多,两者都是为那些其实例可能被另一个线程执行的类而设计的,最主要的差别在于Runnable不会返回线程运算结果,Callable可以(假如线程需要返回运行结果)
public class CallableAndFuture {
public static class CallableThread implements Callable<String> { @Override
public String call() throws Exception {
Thread.sleep(3000);
System.out.println("方法A过了3秒钟才返回数据");
return "A返回结果";
} } public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
CallableThread cThread = new CallableThread();
Future<String> submit = newCachedThreadPool.submit(cThread);
System.out.println(submit.get());
} }
输出:
方法A过了3秒才返回结果
2.FutureTask
先上个FutureTask的类图
FutureTask实现了Runnable和Future,实际上是这两个接口的包装器,所以FutureTask既是Runnable也是Future
我们先写个基本的例子看看FutureTask的使用
Callable<Integer> myComputation = ...;
FutureTask<Integer> task = new FutureTask<Integer>(myComputation);
Thread t = new Thread(task);
t.start();
...
Integer result = task.get(); //获取结果
再看下他的构造方法
相比第一个构造方法,第二个构造方法里面把Runnable转成了callable,所以两个构造方法实现的功能其实都差不多。
FutureTask里面最重要的方法就是get方法了,该方法实际上是对Future的get的实现,下面我们研究下FutureTask的代码
1.FutureTask的状态转换过程:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
2.具体的get方法如下
实现阻塞效果的是awaitDone,具体如下
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
//先定义一堆变量
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
//注意,这个是死循环,阻塞有他一半的功劳
for (;;) {
//刚开始线程还没加入到阻塞队列中这段代码是没有用的,
//这里的作用是当线程已加入队列后,这时候线程被中断了,那就把线程从队列中移除
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
} int s = state;
//任务结束,返回状态
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
//将要结束,那就再等等呗
else if (s == COMPLETING) // cannot time out yet
Thread.yield();
//初始化
else if (q == null)
q = new WaitNode();
//还没加入队列,那就用CAS加进去呗
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
//将线程挂起来,这里就阻塞了
else if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos);
}
else
LockSupport.park(this);
}
}
上述讲述的是FutureTask的阻塞实现,其实还有个疑惑,当线程运行完毕,阻塞会自动解除获取结果,这究竟是怎么实现的呢
我们看看线程的run方法
这里有个ran变量,当获取到执行结果后ran变量为true,再执行set方法
这个可以看出正常情况下FutureTask的状态变化是
NEW -> COMPLETING -> NORMAL
我们再看出 finishCompletion
哈,找到了,类似于AQS的共享锁,这里也做了持续的唤醒
最新文章
- phpcms手机门户相关
- Karma+Jasmine实现自动化单元测试
- 【原】iOS学习之XML与JSON两种数据结构比较和各自底层实现
- WEB安全--渗透笔记
- 怎么让OCR文字识别软件转换别的语言文档
- Oracle并行事务回滚相关参数及视图
- Apollo,Python,Delphi与Oracle之间的神话关系
- 【BZOJ 2005】[Noi2010]能量采集
- Android性能测试
- 继续Python爬虫
- Java随感
- memcached实战系列(四)memcached stats命令 memcached优化
- Nginx CONTENT阶段 autoindex、index模块
- [Linux] Linux的环境变量
- MIME 类型
- 10享元模式Flyweight
- Linux定时任务计划
- 多表连接的三种方式详解 hash join、merge join、 nested loop
- php 多维数据根据某个或多个字段排序
- 软工网络15个人作业4-alpha阶段个人总结(201521123059 叶文柠)
热门文章
- json解析Object
- Failed to mount component: template or render function not defined.
- C/C++字符串相关知识使用整理
- spring学习(二)---依赖注入
- Monkey压力测试操作步骤说明
- Java JSONArray for循环 remove成员的一个好算法
- RK3288 uboot启动流程
- Lesson 22 A glass envelope
- Javascript高级编程学习笔记(27)—— BOM(1)window对象1
- Java核心技术卷一基础知识-第9章-Swing用户界面组件-读书笔记