资讯专栏INFORMATION COLUMN

FutureTask源码分析笔记

PascalXie / 919人阅读

摘要:主要的实现实际上运行还是一个,它对做了一个封装,让开发人员可以从其中获取返回值是有状态的共种状态,四种状态变换的可能和的区别通过方法调用有返回值可以抛异常结果的实现原理判断状态非状态则直接进入返回结果处于状态,则进入等待流程获

主要的实现FutureTask

</>复制代码

  1. # FutureTask实际上运行还是一个runnable,它对callable做了一个封装,让开发人员可以从其中获取返回值;
  2. FutrueTask是有状态的 共7种状态,四种状态变换的可能
  3. NEW -> COMPLETING -> EXCEPTIONAL
  4. NEW -> CANCELLED
  5. NEW -> COMPLETING -> NORMAL
  6. NEW -> INTERRUPTING -> INTERRUPTED
Callable和runnable的区别

</>复制代码

  1. 0. 通过call方法调用;
  2. 1. 有返回值
  3. 2. 可以抛异常
get结果的实现原理

</>复制代码

  1. 1. 判断状态;
  2. 2. 非NEW,COMPLETING状态则直接 进入report返回结果;
  3. 3. 处于NEW,COMPLETING状态,则进入等待awaitDone();
3.x awaitDone 流程

</>复制代码

  1. 3.1. 获取等待的超时时间deadline
  2. 3.2. 进入自旋
  3. 3.3. 判断线程是否被中断:如果被中断则移出等待waiters队列;并抛出异常;
  4. 3.4. 判断FutrueTask状态:如果">COMPLETING",代表执行完成,进入report;
  5. 3.5. 判断FutrueTask状态:如果"=COMPLETING",让出CPU执行Thread.yield();
  6. 3.6. 为当前线程创建一个node节点;
  7. 3.7. 将当前线程WaitNode加入等待队列waiters中;
  8. 3.8. 判断是否超时;
  9. 3.9. 通过LockSupport.park挂起线程,等待运行许可;
  10. 4. report返回执行结果:如果一切正常就返回执行结果,否则返回Exception;
run具体执行原理如下:

</>复制代码

  1. 1. 判断状态是否正常,避免重复执行;
  2. 2. 调用callable的call()方法;
  3. 3. 修改执行状态;保存执行结果;并通知正在等待get的线程;
  4. ## 3.x通知机制finishCompletion
  5. 3.1. 获取所有waiters的集合;
  6. 3.2. 通过cas 拿到执行权;
  7. 3.3. 循环遍历所有等待的线程,通过LockSupport.unpark 唤醒其执行;
Callable和Future的实现原理(JDK8源码分析) 1. cancel 取消执行

</>复制代码

  1. public boolean cancel(boolean mayInterruptIfRunning) {
  2. // 判断状态:只有刚创建的情况下才能取消
  3. // mayInterruptIfRunning:是否中断当前正在运行这个FutureTask的线程;
  4. if (!(state == NEW &&
  5. UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
  6. mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
  7. return false;
  8. try { // in case call to interrupt throws exception
  9. // 如果要中断当前线程,则对runner发布interrupt信号;
  10. if (mayInterruptIfRunning) {
  11. try {
  12. Thread t = runner;
  13. if (t != null)
  14. t.interrupt();
  15. } finally { // final state
  16. // 修改状态为:已经通知线程进行中断
  17. UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
  18. }
  19. }
  20. } finally {
  21. // 通知其他在等待结果的线程
  22. finishCompletion();
  23. }
  24. return true;
  25. }
2. run

</>复制代码

  1. public void run() {
  2. // 判断状态及设置futuretask归属的线程
  3. if (state != NEW ||
  4. !UNSAFE.compareAndSwapObject(this, runnerOffset,
  5. null, Thread.currentThread()))
  6. return;
  7. try {
  8. Callable c = callable;
  9. if (c != null && state == NEW) {
  10. V result;
  11. boolean ran;
  12. try {
  13. // 执行Callable
  14. result = c.call();
  15. // 标记为执行成功
  16. ran = true;
  17. } catch (Throwable ex) {
  18. result = null;
  19. // 标记为执行不成功
  20. ran = false;
  21. // 设置为异常状态,并通知其他在等待结果的线程
  22. setException(ex);
  23. }
  24. // 如果执行成功,修改状态为正常,并通知其他在等待结果的线程
  25. if (ran)
  26. set(result);
  27. }
  28. } finally {
  29. // runner must be non-null until state is settled to
  30. // prevent concurrent calls to run()
  31. runner = null;
  32. // state must be re-read after nulling runner to prevent
  33. // leaked interrupts
  34. int s = state;
  35. // 如果状态为准备发起中断信号或者已经发出中断信号,则让出CPU(Thread.yield())
  36. if (s >= INTERRUPTING)
  37. handlePossibleCancellationInterrupt(s);
  38. }
  39. }
3. get

</>复制代码

  1. public V get() throws InterruptedException, ExecutionException {
  2. int s = state;
  3. // 如果还没执行完,则等待
  4. if (s <= COMPLETING)
  5. s = awaitDone(false, 0L);
  6. // 通过report取结果
  7. return report(s);
  8. }
3.1 report 取执行结果

</>复制代码

  1. private V report(int s) throws ExecutionException {
  2. Object x = outcome;
  3. // 如果一切正常,则返回x(x是callable执行的结果outcome)
  4. if (s == NORMAL)
  5. return (V)x;
  6. // 如果被取消,则抛出已取消异常
  7. if (s >= CANCELLED)
  8. throw new CancellationException();
  9. // 否则抛出执行异常
  10. throw new ExecutionException((Throwable)x);
  11. }
3.2 awaitDone 等待FutureTask执行结束

</>复制代码

  1. private int awaitDone(boolean timed, long nanos)
  2. throws InterruptedException {
  3. // 记录等待超时的时间
  4. final long deadline = timed ? System.nanoTime() + nanos : 0L;
  5. // 多个在等待结果的线程,通过一个链表进行保存,waitNode就是每个线程在链表中的节点;
  6. WaitNode q = null;
  7. boolean queued = false;
  8. // 死循环...也可以说是自旋锁同步
  9. for (;;) {
  10. // 判断当前这个调用get的线程是否被中断
  11. if (Thread.interrupted()) {
  12. // 将当前线程移出队列
  13. removeWaiter(q);
  14. throw new InterruptedException();
  15. }
  16. int s = state;
  17. // 如果状态非初创或执行完毕了,则跳出循环,通过report()取执行结果
  18. if (s > COMPLETING) {
  19. if (q != null)
  20. q.thread = null;
  21. return s;
  22. }
  23. // 如果状态等于已执行,让出CPU执行,等待状态变为正常结束
  24. else if (s == COMPLETING) // cannot time out yet
  25. Thread.yield();
  26. // 如果当前线程还没有创建对象的waitNode节点,则创建一个
  27. else if (q == null)
  28. q = new WaitNode();
  29. // 如果当前线程对应的waitNode还没有加入到等待链表中,则加入进去;
  30. else if (!queued)
  31. queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
  32. q.next = waiters, q);
  33. // 如果有设置等待超时时间,则通过parkNanos挂起当前线程,等待继续执行的信号
  34. else if (timed) {
  35. nanos = deadline - System.nanoTime();
  36. if (nanos <= 0L) {
  37. removeWaiter(q);
  38. return state;
  39. }
  40. LockSupport.parkNanos(this, nanos);
  41. }
  42. // 通过park挂起当前线程,等待task执行结束后给它发一个继续执行的信号(unpark)
  43. else
  44. LockSupport.park(this);
  45. }
  46. }
4. finishCompletion 通知所有在等待结果的线程

</>复制代码

  1. private void finishCompletion() {
  2. // assert state > COMPLETING;
  3. // 遍历所有正在等待执行结果的线程
  4. for (WaitNode q; (q = waiters) != null;) {
  5. if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
  6. for (;;) {
  7. Thread t = q.thread;
  8. if (t != null) {
  9. q.thread = null;
  10. // unpark,发布一个让它继续执行的“许可”
  11. LockSupport.unpark(t);
  12. }
  13. WaitNode next = q.next;
  14. if (next == null)
  15. break;
  16. q.next = null; // unlink to help gc
  17. q = next;
  18. }
  19. break;
  20. }
  21. }
  22. done();
  23. callable = null; // to reduce footprint
  24. }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69216.html

相关文章

  • Java Executors 源码分析

    摘要:表示一个异步任务的结果,就是向线程池提交一个任务后,它会返回对应的对象。它们分别提供两个重要的功能阻塞当前线程等待一段时间直到完成或者异常终止取消任务。此时,线程从中返回,然后检查当前的状态已经被改变,随后退出循环。 0 引言 前段时间需要把一个C++的项目port到Java中,因此时隔三年后重新熟悉了下Java。由于需要一个通用的线程池,自然而然就想到了Executors。 用了...

    itvincent 评论0 收藏0
  • 追踪解析 FutureTask 源码

    摘要:零前期准备文章异常啰嗦且绕弯。版本版本简介是中默认的实现类,常与结合进行多线程并发操作。所以方法的主体其实就是去唤醒被阻塞的线程。本文仅为个人的学习笔记,可能存在错误或者表述不清的地方,有缘补充 零 前期准备 0 FBI WARNING 文章异常啰嗦且绕弯。 1 版本 JDK 版本 : OpenJDK 11.0.1 IDE : idea 2018.3 2 ThreadLocal 简介 ...

    xcc3641 评论0 收藏0
  • jvm原理

    摘要:在之前,它是一个备受争议的关键字,因为在程序中使用它往往收集器理解和原理分析简称,是后提供的面向大内存区数到数多核系统的收集器,能够实现软停顿目标收集并且具有高吞吐量具有更可预测的停顿时间。 35 个 Java 代码性能优化总结 优化代码可以减小代码的体积,提高代码运行的效率。 从 JVM 内存模型谈线程安全 小白哥带你打通任督二脉 Java使用读写锁替代同步锁 应用情景 前一阵有个做...

    lufficc 评论0 收藏0
  • FutureTask源码解析(2)——深入理解FutureTask

    摘要:本文的源码基于。人如其名,包含了和两部分。而将一个任务的状态设置成终止态只有三种方法我们将在下文的源码解析中分析这三个方法。将栈中所有挂起的线程都唤醒后,下面就是执行方法这个方法是一个空方 前言 系列文章目录 有了上一篇对预备知识的了解之后,分析源码就容易多了,本篇我们就直接来看看FutureTask的源码。 本文的源码基于JDK1.8。 Future和Task 在深入分析源码之前,我...

    Harpsichord1207 评论0 收藏0
  • FutureTask源码分析

    摘要:从而可以启动和取消异步计算任务查询异步计算任务是否完成和获取异步计算任务的返回结果。原理分析在分析中我们没有看它的父类,其中有一个方法,返回一个,说明该方法可以获取异步任务的返回结果。 FutureTask介绍 FutureTask是一种可取消的异步计算任务。它实现了Future接口,代表了异步任务的返回结果。从而FutureTask可以启动和取消异步计算任务、查询异步计算任务是否完成...

    luqiuwen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<