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. 30. Substring with Concatenation of All Words (JAVA)

    You are given a string, s, and a list of words, words, that are all of the same length. Find all sta ...

  2. How Does Caching Work in AFNetworking? : AFImageCache & NSUrlCache Explained

    http://blog.originate.com/blog/2014/02/20/afimagecache-vs-nsurlcache/

  3. Axiso解决跨域访问

    问题: 在项目中需要需要讲本地项目去请求一个URL接口获取数据 例如: 本地请求地址:http://127.0.0.1:19323/site/info.json 请求Url地址:http://www. ...

  4. 切入点表达式execution()

    用于描述方法 [掌握] 语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常) 修饰符,一般省略 public                公共方法 *         ...

  5. vscode 黑屏及类名报错解决方案

    1.安装vscode之后打开黑屏,解决方案如下图,右键--属性--兼容性--勾选上 2.vscode 类名总报错 是ES2017的语法修饰器引起vscode警告. 解除的方法如果你使用的typescr ...

  6. linux c下的c文件 h文件 o文件 so文件 a文件 可执行文件 gcc使用

    linux下c语言工程: c文件:主要每个模块的原代码都在c文件中. h文件:每个c文件都跟着一个h文件,h文件的作用是放着c文件中函数的声明,结构体的定义,宏的定义等. o文件:目标文件.每个文件经 ...

  7. python基础操作---list

    #coding:utf-8 list1 = ['physics', 'chemistry', 1997, 2000]; list2 = [1, 2, 3, 4, 5 ]; list3 = [" ...

  8. 图像描点标注-labelme的安装及使用

    1.直接使用pip安装lebelme pip install labelme 2.labelme的使用 找到labelme的安装路径,先找到python的安装路径如我的,C:\Users\Think\ ...

  9. uwsgi支持http长链接

    http1.1支持长链接,而http1.0不支持,所以,在切换http版本号或者升级服务端版本时候,尤其要注意这个造成的影响. 当客户端以http1.1长链接方式连接服务端时,服务端如果不支持1.1, ...

  10. vimdiff 可视化比较工具

    1.命令功能 vimdiff调用vim打开文件,可以同时打开2~4个文件,最多4个文件,且会以不同的颜色来区分文件的差异. 2.语法格式 vimdiff file1 file2 3.使用范例 [roo ...