文档章节

FutureTask源码分析

Hosee
 Hosee
发布于 2018/11/26 16:55
字数 716
阅读 323
收藏 2

问题

本文通过源码阐述两个问题

  1. WaitNode是干嘛的
  2. 为什么JDK1.7中FutureTask放弃了使用了AQS

其他源码请查看其他Blog

WaitNode

Treiber stack

Treiber Stack在 R. Kent Treiber在1986年的论文Systems Programming: Coping with Parallelism中首次出现。它是一种无锁并发栈,其无锁的特性是基于CAS原子操作实现的。

下面给出的Java语言实现为《Java并发编程实战》一书的15.4.1小结中的实现。Treiber Stack的实现套路很简单,就是CAS+重试,不需要任何注释就能轻松的看懂代码。

public class TreiberStack<E> {
    AtomicReference<Node<E>> top = new AtomicReference<>();

    /**
     * 入栈
     * @param item E
     */
    public void push(E item) {
        Node<E> newHead = new Node<E>(item);
        Node<E> oldHead;
        //使用CAS操作循环设置栈头,保证在多线程情况下push新节点时新节点是正确的栈头
        do {
            oldHead = top.get();
            newHead.next = oldHead;
			//如果在循环中oldHead没有变化,即oldHead值为期望值,则更新
        } while (!top.compareAndSet(oldHead, newHead));
    }

    /**
     * 出栈
     * @return E
     */
    public E pop() {
        Node<E> oldHead;
        Node<E> newHead;
        //使用CAS操作循环设置栈头,保证在多线程情况下pop的时候取到的是最头的节点
        do {
            oldHead = top.get();
            if (oldHead == null) {
                return null;
            }
            newHead = oldHead.next;
        } while (!top.compareAndSet(oldHead, newHead));
        return oldHead.item;
    }

    private static class Node<E> {
        final E item;
        Node<E> next;

        Node(E item) {
            this.item = item;
        }
    }
}

WaitNode是干嘛的

/*Treiber椎,用于保存由于调用Future.get方法而阻塞的线程*/
private volatile WaitNode waiters;
static final class WaitNode {
     volatile Thread thread;
     volatile WaitNode next;
     WaitNode() { thread = Thread.currentThread(); }
}

每当一个线程调用Future.get去获取任务的执行结果时,如果当前任务还没有执行结束、还没有被取消或者执行中未抛出异常。将产生一个新的WaitNode类型的节点,该节点持有调用Future.get方法的线程的引用,放入到Treiber stack中。FutureTask成员变量waiters更新为最新的WaitNode节点。如下图。

为什么放弃了使用了AQS

源码注释:

/*
 * Revision notes: This differs from previous versions of this
 * class that relied on AbstractQueuedSynchronizer, mainly to
 * avoid surprising users about retaining interrupt status during
 * cancellation races. Sync control in the current design relies
 * on a "state" field updated via CAS to track completion, along
 * with a simple Treiber stack to hold waiting threads.
 *
 * Style note: As usual, we bypass overhead of using
 * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
 */

从Java1.7开始Doug Lea对FutureTask进行了重写,不使用AQS去维护WaitNode,而改用上文提到的Treiber Stack,即通过CAS来维护内部的竞争状态,当然也包括了waiters(队头)的状态。 这么做主要是为了在需要竞争时保留中断状态。

Reference

  1. https://www.cnblogs.com/micrari/p/7719408.html
  2. https://blog.csdn.net/u011236357/article/details/78339410?locationNum=5&fps=1
  3. https://zhuanlan.zhihu.com/p/40047276
  4. https://www.zhihu.com/question/60123950

© 著作权归作者所有

Hosee
粉丝 621
博文 135
码字总数 209956
作品 0
杭州
程序员
私信 提问
加载中

评论(0)

Android异步任务AsyncTask原理(基于Android9.0)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SilenceOO/article/details/89304880 AsyncTask原理 前言 在Android开发中经常会通过线程去执行耗时的任务,并...

小黄花的故事
2019/04/15
0
0
FutureTask在线程池中应用和源码解析

原文出处:hcy0411 FutureTask 是一个支持取消的异步处理器,一般在线程池中用于异步接受callable返回值。 主要实现分三部分: 封装 Callable,然后放到线程池中去异步执行->run。 获取结果-...

hcy0411
2018/11/20
0
0
Java并发编程笔记之FutureTask源码分析

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异...

狂小白
2018/07/13
0
0
源码|使用FutureTask的正确姿势

线程池的实现核心之一是FutureTask。在提交任务时,用户实现的Callable实例task会被包装为FutureTask实例ftask;提交后任务异步执行,无需用户关心;当用户需要时,再调用FutureTask#get()获...

猴子007
2017/11/20
0
0
死磕 java线程系列之线程池深入解析——未来任务执行流程

(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本。 注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类。 简介 前面我们一起学习了线程池中普通任务的执...

彤哥读源码
2019/11/04
94
0

没有更多内容

加载失败,请刷新页面

加载更多

略谈分布式系统中的容器设计模式

本文作者:zytan_cocoa 略谈分布式系统中的容器设计模式 谭中意 2020/3/5 前言:云原生(Cloud Native)不仅仅是趋势,更是现在进行时,它是构建现代的,可弹性伸缩的,快速迭代的计算网络服...

百度开发者中心
03/11
5
0
OSChina 周三乱弹 —— 小姐姐的领带有点带歪了,请帮忙正一下

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @薛定谔的兄弟 :分享洛神有语创建的歌单「我喜欢的音乐」: 《アイタクテ -voice & piano-》- 和紗 手机党少年们想听歌,请使劲儿戳(这里) ...

小小编辑
今天
21
0
对象名称前的单下划线和双下划线是什么意思?

问题: Can someone please explain the exact meaning of having leading underscores before an object's name in Python? 有人可以解释一下在Python中对象名称前加下划线的确切含义吗? ......

技术盛宴
今天
29
0
Redis命令行参数大全

[TOC] Redis命令行参数大全 CLI工具的类型 可执行文件 作用 redis-server Redis Srver相关 redis-cli Redis命令行工具 redis-benchmark 基准测试工具 redis-check-aof AOF持久化文件检测工具...

我爱吃炒鸡
今天
20
0
RHEL8和CentOS8怎么重启网络

RHEL8和CentOS8怎么重启网络 本文主要讲解如何重启RHEL 8或者CentOS 8网络以及如何解决RHEL8和CentOS8系统的网络管理服务报错,当我们安装好RHEL 8或者 CentOS 8,重启启动网络时,会出现以下...

独钓渔
今天
42
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部