这三个都是自 JDK1.5 开始加入到 java.util.concurrent.atomic 下面的。他们都可以在 lock-free 的情况下以原子的方式更新对象引用。

一、AtomicReference

以原子方式更新对象引用。

static class User {
private int age; public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public User(int age) {
this.age = age;
}
} public static void main(String[] args) {
User user1 = new User(10);
User user2 = new User(20); AtomicReference<User> atomicReference = new AtomicReference<>(user1);
System.out.println(atomicReference.get().getAge()); atomicReference.compareAndSet(user1, user2);
System.out.println(atomicReference.get().getAge());
}

二、AtomicStampedReference

解决了 AtomicReference 中 CAS 操作存在的 ABA 问题。

public static void main(String[] args) {
User user1 = new User(10);
User user2 = new User(20); AtomicStampedReference<User> stampedReference = new AtomicStampedReference<>(user1, 1); int[] stamp = new int[1];
// 获取引用对象和对应的版本号
System.out.println(stampedReference.get(stamp).getAge()); int oldStamp = stamp[0];
// 预期引用,新引用,预期版本号,新版本号
stampedReference.compareAndSet(user1, user2, oldStamp, 2); System.out.println(stampedReference.get(stamp).getAge());
}

內部定义了一个 Pair 对象,相当于给引用加了一个版本号

public class AtomicStampedReference<V> {

    private static class Pair<T> {
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
} private volatile Pair<V> pair; public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}

替换时的逻辑,当引用和版本号都相同时才使用 CAS 替换

public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) {
Pair<V> current = pair;
return expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
} private boolean casPair(Pair<V> cmp, Pair<V> val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}

三、AtomicMarkableReference

相对于 AtomicStampedReference,有时候,我们并不关心引用变量更改了几次,只是单纯的关心是否更改过

public static void main(String[] args) {
User user1 = new User(10);
User user2 = new User(20); AtomicMarkableReference<User> stampedReference = new AtomicMarkableReference<>(user1, false); boolean[] stamp = new boolean[1];
// 获取引用对象和对应的状态
System.out.println(stampedReference.get(stamp).getAge()); boolean oldStamp = stamp[0];
// 预期引用,新引用,预期状态,新状态
stampedReference.compareAndSet(user1, user2, oldStamp, false); System.out.println(stampedReference.get(stamp).getAge());
}

内部和 AtomicStampedReference 一样

public class AtomicMarkableReference<V> {

    private static class Pair<T> {
final T reference;
final boolean mark;
private Pair(T reference, boolean mark) {
this.reference = reference;
this.mark = mark;
}
static <T> Pair<T> of(T reference, boolean mark) {
return new Pair<T>(reference, mark);
}
} private volatile Pair<V> pair; public AtomicMarkableReference(V initialRef, boolean initialMark) {
pair = Pair.of(initialRef, initialMark);
} public boolean compareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedMark == current.mark &&
((newReference == current.reference &&
newMark == current.mark) ||
casPair(current, Pair.of(newReference, newMark)));
} private boolean casPair(Pair<V> cmp, Pair<V> val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}

https://segmentfault.com/a/1190000015831791

AtomicReference、AtomicStampedReference 和 AtomicMarkableReference的更多相关文章

  1. ABA问题怎么解:AtomicStampedReference和AtomicMarkableReference

    本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 并发编程的基石--CAS机制这篇文章中介绍到CAS机制有 ...

  2. AtomicReference,AtomicStampedReference与AtomicMarkableReference的区别

    AtomicReference 通过volatile和Unsafe提供的CAS函数实现原子操作. 自旋+CAS的无锁操作保证共享变量的线程安全 value是volatile类型,这保证了:当某线程修改 ...

  3. AtomicStampedReference、AtomicMarkableReference 区别

    AtomicMarkableReference 描述的是更加简单的是与否的关系,它的定义就是将数据变换为true 或 false,通常ABA问题只有两种状态,AtomicMarkableReferen ...

  4. Java并发编程-总纲

    Java 原生支持并发,基本的底层同步包括:synchronized,用来标示一个方法(普通,静态)或者一个块需要同步执行(某一时刻,只允许一个线程在执行代码块).volatile,用来标识一个变量是 ...

  5. 非阻塞同步机制与CAS操作

    锁的劣势 Java在JDK1.5之前都是靠synchronized关键字保证同步的,这种通过使用一致的锁定协议来协调对共享状态的访问,可以确保无论哪个线程 持有守护变量的锁,都采用独占的方式来访问这些 ...

  6. 还在用Synchronized?Atomic你了解不?

    前言 只有光头才能变强 之前已经写过多线程相关的文章了,有兴趣的同学可以去了解一下: https://github.com/ZhongFuCheng3y/3y/blob/master/src/thre ...

  7. Java面试 32个核心必考点完全解析

    目录 课程预习 1.1 课程内容分为三个模块 1.2 换工作面临问题 1.3 课程特色 课时1:技术人职业发展路径 1.1 工程师发展路径 1.2 常见技术岗位划分 1.3 面试岗位选择 1.4 常见 ...

  8. 三、原子变量与CAS算法

    原子变量:jdk1.5 后 java.util.concurrent.atomic 包下提供了常用的原子变量: - AtomicBoolean - AtomicInteger - AtomicLong ...

  9. Java多线程并发编程一览笔录

    线程是什么? 线程是进程中独立运行的子任务. 创建线程的方式 方式一:将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法 方式二:声明实现 Runnable 接口的类.该 ...

随机推荐

  1. set 集合的函数调用

    方法 意义 S.add(e) 在集合中添加一个新的元素e:如果元素已经存在,则不添加 S.remove(e) 从集合中删除一个元素,如果元素不存在于集合中,则会产生一个KeyError错误 S.dis ...

  2. spring 整合mongodb报NoSuchMethodError错误

    刚开始通过网上查到相关的资料进行了一些配置,参考链接:http://www.open-open.com/lib/view/open1454374782167.html maven的dependenci ...

  3. djnago中间件

    前言 在form表单中当我们提交表单时会有这样的错误>>>>请求post时候的会出现403 forbidden,那我们就说说这个类中间件,(csrf只是中间件的一种) 以前我们 ...

  4. Ajax返回数据却一直进入error(已经解决)

    做asp.net项目  使用ajax $.ajax({ url: '../Music/Default2.aspx?Types=' + type + '&texts=' + text + '', ...

  5. HAL库 TIM计数器及中断开启过程

    1.初始化TIM基本计数器参数 void MX_TIM2_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig = {}; TIM_Master ...

  6. python .pth 文件 和 site 模块

    python .pth 文件 和 site 模块 .pth 文件 该文件位于 python 的 /Lib/site-packages 目录下,可以有多个,在 .pth 文件中可以把其它目录添加到 sy ...

  7. 从Excel中读取数据并批量写入MySQL数据库(基于MySQLdb)

    一.Excel内容如下,现在需要将Excel中的数据全部写入的MySQL数据库中: 二.连接MySQL的第三方库使用的是“MySQLdb”,代码如下: # -*- coding:utf-8 -*-im ...

  8. Elasticsearch:fuzzy 搜索 (模糊搜索)

    在实际的搜索中,我们有时候会打错字,从而导致搜索不到.在Elasticsearch中,我们可以使用fuzziness属性来进行模糊查询,从而达到搜索有错别字的情形. match查询具有"fu ...

  9. mali gpu debugger

    https://community.arm.com/developer/tools-software/graphics/b/blog/posts/accelerating-mali-gpu-analy ...

  10. mongodb命令---创建数据库,插入文档,更新文档记录

    创建数据库----基本就是使用隐式创建 例如 use 你定义的数据库名, use dingsmongo  如果你使用的是studio 3T软件,那直接选中右侧的地址栏点击右键选择Add Databas ...