AtomicReference、AtomicStampedReference 和 AtomicMarkableReference
这三个都是自 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的更多相关文章
- ABA问题怎么解:AtomicStampedReference和AtomicMarkableReference
本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 并发编程的基石--CAS机制这篇文章中介绍到CAS机制有 ...
- AtomicReference,AtomicStampedReference与AtomicMarkableReference的区别
AtomicReference 通过volatile和Unsafe提供的CAS函数实现原子操作. 自旋+CAS的无锁操作保证共享变量的线程安全 value是volatile类型,这保证了:当某线程修改 ...
- AtomicStampedReference、AtomicMarkableReference 区别
AtomicMarkableReference 描述的是更加简单的是与否的关系,它的定义就是将数据变换为true 或 false,通常ABA问题只有两种状态,AtomicMarkableReferen ...
- Java并发编程-总纲
Java 原生支持并发,基本的底层同步包括:synchronized,用来标示一个方法(普通,静态)或者一个块需要同步执行(某一时刻,只允许一个线程在执行代码块).volatile,用来标识一个变量是 ...
- 非阻塞同步机制与CAS操作
锁的劣势 Java在JDK1.5之前都是靠synchronized关键字保证同步的,这种通过使用一致的锁定协议来协调对共享状态的访问,可以确保无论哪个线程 持有守护变量的锁,都采用独占的方式来访问这些 ...
- 还在用Synchronized?Atomic你了解不?
前言 只有光头才能变强 之前已经写过多线程相关的文章了,有兴趣的同学可以去了解一下: https://github.com/ZhongFuCheng3y/3y/blob/master/src/thre ...
- Java面试 32个核心必考点完全解析
目录 课程预习 1.1 课程内容分为三个模块 1.2 换工作面临问题 1.3 课程特色 课时1:技术人职业发展路径 1.1 工程师发展路径 1.2 常见技术岗位划分 1.3 面试岗位选择 1.4 常见 ...
- 三、原子变量与CAS算法
原子变量:jdk1.5 后 java.util.concurrent.atomic 包下提供了常用的原子变量: - AtomicBoolean - AtomicInteger - AtomicLong ...
- Java多线程并发编程一览笔录
线程是什么? 线程是进程中独立运行的子任务. 创建线程的方式 方式一:将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法 方式二:声明实现 Runnable 接口的类.该 ...
随机推荐
- input type=color 设置颜色
在设置背景色的时候,使用html5 type=color 标签,但是初始值一直都是黑色的,背景如果没有设置的时候,应该是白色,比如文本图元,所以需要设置一个初始的颜色值, 注意: value不实用,怎 ...
- 捕捉Promise reject 错误
var sleep = function (time) { return new Promise(function (resolve, reject) { setTimeout(function () ...
- 转载:Web安全 之 X-Frame-Options响应头配置
转自:https://blog.csdn.net/u013310119/article/details/81064943 项目检测时,安全报告中存在 “X-Frame-Options” 响应头缺失问题 ...
- 使用postman创建Marketing Cloud的Contact
首先在Marketing Cloud的UI上创建一个contact: 观察Chrome开发者工具network标签页里的HTTP请求: https://jerry.gcdemo.hybris.com/ ...
- 多进程之multiprocessing模块和进程池的实现
转载:https://www.cnblogs.com/xiaobeibei26/p/6484849.html Python多进程之multiprocessing模块和进程池的实现 1.利用multip ...
- 使用iframe框架时,实现子页面内跳转到整个页面,而不是在子页面内跳转
首先先来描述一下我所遇到的问题,我在一个首页的index.jsp页面中用到了iframe框架,见下图 在iframe中引入jsp页面的路径,是几个iframe框架组合成的一个完整的页面,但是他们的存在 ...
- java——double数据精度问题
代码:使用BigDecimal来代替double public class BigDecimalUtil { public static BigDecimal add(double v1,double ...
- bat 获取当前目录的父目录
bat 获取当前目录的父目录 @echo off echo batchfile=%0 echo full=%~f0 setlocal for %%d in (%~dp0.) do set Direct ...
- string::crbegin string::crend
const_reverse_iterator crbegin() const noexcept;功能:crbegin是最后一个字符,crend第一个字符的前一个.迭代器向左移动是“+”,向右移动是“- ...
- Tomcat下配置JNDI的三种方式
最近在整理项目上的配置文件,正好看到了数据源配置,想着配置方式有多种,便趁热打铁,记录下常规的Tomcat配置数据源的方式 1.单个工程配置 找到Tomcat下的server.xml文件,在Conte ...