AtomicReference

AtomicReference 能解决什么问题?什么时候使用 AtomicReference?

1)AtomicReference 可以原子更新引用对象。
2)compareAndSet 操作是一条 CPU 指令,不会发生上下文切换,执行效率高。
使用锁保证对象同步时,会触发一次系统调用和上下文切换,执行效率低。

如何使用 AtomicReference?

1)多线程环境下需要并发修改对象的多个属性时,使用 AtomicReference【
读取、修改、更新需要在同一个循环中,并根据 compareAndSet 的结果来判断是否要继续自旋】。

使用 AtomicReference 有什么风险?

1)高并发场景下,自旋 CAS 长时间失败会导致 CPU 飙升

AtomicReference 核心操作的实现原理?

创建实例

    private static final VarHandle VALUE;
static {
try {
final MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
} catch (final ReflectiveOperationException e) {
throw new Error(e);
}
} /**
* volatile 引用值
*/
private volatile V value; /**
* 基于初始对象 initialValue 创建一个 AtomicReference 实例
*/
public AtomicReference(V initialValue) {
value = initialValue;
} /**
* 创建一个关联对象为 null 的 AtomicReference 实例
*/
public AtomicReference() {
}

尝试原子更新

    /**
* 原子的将引用值设置为 newValue,如果旧值 == expectedValue,设置成功返回 true,否则返回 false。
*
* @param expectedValue 期望值
* @param newValue 新值
*/
public final boolean compareAndSet(V expectedValue, V newValue) {
return AtomicReference.VALUE.compareAndSet(this, expectedValue, newValue);
}

读取当前值

    /**
* 读取当前值
* with memory effects as specified by {@link VarHandle#getVolatile}.
*/
public final V get() {
return value;
}

原子地将旧值更新为 newValue,并返回旧值

    /**
* 原子地将旧值更新为 newValue,并返回旧值
* with memory effects as specified by {@link VarHandle#getAndSet}.
*/
@SuppressWarnings("unchecked")
public final V getAndSet(V newValue) {
return (V)AtomicReference.VALUE.getAndSet(this, newValue);
}

使用函数式接口 updateFunction 基于旧值计算新值,并将旧值替换为计算值,返回旧值

    /**
* 使用函数式接口 updateFunction 基于旧值计算新值,并将旧值替换为计算值,返回旧值
*/
public final V getAndUpdate(UnaryOperator<V> updateFunction) {
V prev = get(), next = null;
for (boolean haveNext = false;;) {
if (!haveNext) {
next = updateFunction.apply(prev);
}
if (weakCompareAndSetVolatile(prev, next)) {
return prev;
}
haveNext = prev == (prev = get());
}
} /**
* 如果当前值==expectedValue,则尝试原子地将其更新为 newValue,更新成功返回 true
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSet}.
*/
public final boolean weakCompareAndSetVolatile(V expectedValue, V newValue) {
return AtomicReference.VALUE.weakCompareAndSet(this, expectedValue, newValue);
}

使用函数式接口 updateFunction 基于旧值计算新值,并将旧值替换为计算值,返回新值

    /**
* 使用函数式接口 updateFunction 基于旧值计算新值,并将旧值替换为计算值,返回新值
*/
public final V updateAndGet(UnaryOperator<V> updateFunction) {
V prev = get(), next = null;
for (boolean haveNext = false;;) {
if (!haveNext) {
next = updateFunction.apply(prev);
}
if (weakCompareAndSetVolatile(prev, next)) {
return next;
}
haveNext = prev == (prev = get());
}
}

使用函数式接口 accumulatorFunction 基于旧值和形参 x 计算新值,并将旧值替换为计算值,返回旧值

    /**
* 使用函数式接口 accumulatorFunction 基于旧值和形参 x 计算新值,并将旧值替换为计算值,返回旧值
*/
public final V getAndAccumulate(V x,
BinaryOperator<V> accumulatorFunction) {
V prev = get(), next = null;
for (boolean haveNext = false;;) {
if (!haveNext) {
next = accumulatorFunction.apply(prev, x);
}
if (weakCompareAndSetVolatile(prev, next)) {
return prev;
}
haveNext = prev == (prev = get());
}
}

使用函数式接口 accumulatorFunction 基于旧值和形参 x 计算新值,并将旧值替换为计算值,返回新值

    /**
* 使用函数式接口 accumulatorFunction 基于旧值和形参 x 计算新值,并将旧值替换为计算值,返回新值
*/
public final V accumulateAndGet(V x,
BinaryOperator<V> accumulatorFunction) {
V prev = get(), next = null;
for (boolean haveNext = false;;) {
if (!haveNext) {
next = accumulatorFunction.apply(prev, x);
}
if (weakCompareAndSetVolatile(prev, next)) {
return next;
}
haveNext = prev == (prev = get());
}
}

AtomicReference 源码分析的更多相关文章

  1. Java并发包源码分析

    并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力.如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互性将大大改善.现代的PC都有多个CPU或一个CPU中有多个 ...

  2. rxjava源码分析

    RXjava响应式编程 此文作者大暴雨原创,转载请注明出处. 如果线程的知识不是很丰富,请先查看     rxjava源码中的线程知识  一文 rxjava总结就是:异步实现主要是通过扩展观察者模式 ...

  3. Java高并发之无锁与Atomic源码分析

    目录 CAS原理 AtomicInteger Unsafe AtomicReference AtomicStampedReference AtomicIntegerArray AtomicIntege ...

  4. zuul源码分析-探究原生zuul的工作原理

    前提 最近在项目中使用了SpringCloud,基于zuul搭建了一个提供加解密.鉴权等功能的网关服务.鉴于之前没怎么使用过Zuul,于是顺便仔细阅读了它的源码.实际上,zuul原来提供的功能是很单一 ...

  5. RxJava2 中多种取消订阅 dispose 的方法梳理( 源码分析 )

    Github 相关代码: Github地址 一直感觉 RxJava2 的取消订阅有点混乱, 这样也能取消, 那样也能取消, 没能系统起来的感觉就像掉进了盘丝洞, 迷乱… 下面说说这几种情况 几种取消的 ...

  6. 死磕 java并发包之AtomicStampedReference源码分析(ABA问题详解)

    问题 (1)什么是ABA? (2)ABA的危害? (3)ABA的解决方法? (4)AtomicStampedReference是什么? (5)AtomicStampedReference是怎么解决AB ...

  7. SparkRPC源码分析之RPC管道与消息类型

    SparkRPC源码分析之RPC管道与消息类型我们前面看过了netty基础知识扫盲,那我们应该明白,ChannelHandler这个组件内为channel的各种事件提供了处理逻辑,也就是主要业务逻辑写 ...

  8. 源码分析 RocketMQ DLedger(多副本) 之日志复制(传播)

    目录 1.DLedgerEntryPusher 1.1 核心类图 1.2 构造方法 1.3 startup 2.EntryDispatcher 详解 2.1 核心类图 2.2 Push 请求类型 2. ...

  9. RxJava 2.x 源码分析

    本次分析的 RxJava 版本信息如下: 12 implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'implementation 'io.reac ...

随机推荐

  1. PBOC第八部分和第十一部分关于TYPEA总结(一)——初始化和防冲突(ISO14443-3)

    PBOC第八部分和第十一部分关于TYPEA总结(一) ——初始化和防冲突(ISO14443-3) 第八部分 与应用无关的非接触式规范 ISO14443(1~4) 第十一部分 非接触式IC卡通讯规范 在 ...

  2. linux基本命令之文件浏览(cat,more,less,tail,head),文件操作命令(cp,mv,rm,find)

    linux文件浏览,文件操作命令 文件管理之文件浏览命令 1.cat命令:显示文本文件所有内容 格式:cat 文件名 适用场景:适合只有少量数据的文件,例如只有几行内容的可以使用此命令. 2.more ...

  3. css水平垂直居中问题

    水平居中: 行内元素:text-align:center; 块级元素:magin:0 auto; 子元素设置:position:absolute;  left:50%;  transform:tran ...

  4. MySQL索引优化(索引三表优化案例)

    建表SQL phone.book表建立索引 [关联优化查询建议] 1.保证被驱动表的join字段已经被索引 被驱动表  join 后的表为被驱动表  (需要被查询) 2.left join 时,选择小 ...

  5. makeinfo - 翻译 Texinfo 文档

    SYNOPSIS 总览 makeinfo [OPTION]... TEXINFO-FILE... DESCRIPTION 描述 将 Texinfo 源文档翻译为各种其他格式,默认是可以用 Emacs ...

  6. 004-sed 命令使用

    sed 命令使用 主要作用是用来将数据进行选取,替换,删除,新增的命令,与vim类似 选项: -n : 只显示经过sed处理的数据,打印到屏幕 -e: 运行多个条件同时运行 -i: 直接修改文件 -p ...

  7. PHP使用HighChart生成股票K线图详解

    本人qq群也有许多的技术文档,希望可以为你提供一些帮助(非技术的勿加). QQ群:   281442983 (点击链接加入群:http://jq.qq.com/?_wv=1027&k=29Lo ...

  8. python基本数据类型常用方法

    python基本数据类型 1.整型 1.1 int 1.2 bit_lenght # 当前数字的二进制位数,至少用n位表示 r = age.bit_length() >>> a = ...

  9. Django【第5篇】:Django之ORM数据库操作

    django之ORM数据库操作 一.ORM介绍 映射关系: 表名 -------------------->类名 字段-------------------->属性 表记录-------- ...

  10. 锁,threading local,以及生产者和消费者模型

    1.锁:Lock(一次放行一个) 线程安全,多线程操作时,内部会让所有的线程排队处理. 线程不安全:+人=>排队处理 以后锁代码块 v=[] lock=threading.Lock()#声明锁 ...