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 接口的类.该 ...
随机推荐
- com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction 问题解决
有两种设置方法 第一种在mysql的配置文件中加入,然后重启mysql innodb_lock_wait_timeout = 500 第二种直接执行如下命令 set global innodb_loc ...
- php-amqplib库操作RabbitMQ
RabbitMQ基本原理 首先,建议去大概了解下RabbitMQ(以下简称mq)的基本工作原理,可以参考这篇文章最主要的几个对象如下 对象名称 borker 相当于mq server channe ...
- 记录一次ABP下载模板的坑
1.拉取ABP官网的模板的最新代码,我的代码结构是这样的 https://aspnetboilerplate.com/Templates 环境安装的部分我就不说明了.node.js npm 等等部分 ...
- select —— poll —— epoll
import socket,select s=socket.socket() s.setblocking(False) s.setsockopt(socket.SOL_SOCKET,socket. ...
- 智能指针原理及实现(2)unique_ptr
只允许基础指针的一个所有者. 可以移到新所有者(具有移动语义),但不会复制或共享(即我们无法得到指向同一个对象的两个unique_ptr). 替换已弃用的 auto_ptr. 相较于 boost::s ...
- 【异常】azkaban.executor.ExecutorManagerException: No active executors found
1 azkaban启动异常 没有找到活动的executors,需在MySQL数据库里设置端口为12321的executors表的active为1 update azkaban.executors ...
- 浅谈nginx简介和应用场景
简介 nginx是一款轻量级的web服务器,它是由俄罗斯的程序设计师伊戈尔·西索夫所开发. nginx相比于Tomcat性能十分优秀,能够支撑5w的并发连接(而Tomcat只能支撑200-400),并 ...
- web开发:javascript动画
一.鼠标事件 二.js盒模型 三.鼠标拖拽 四.键盘事件 五.其他时间应用 六.定时器 七.定时器案例 八.随机数 一.鼠标事件 <!DOCTYPE html> <html> ...
- (转)android(SignalA)接收.net(SignalR)推送过来的消息
从网络上搜索到的Demo,自己进行了稍微的改动 Signala类库从https://github.com/erizet/SignalA获得,不过相关引用有错误,需要手动修正. 下载相关源码 packa ...
- intellij idea打包出来的jar包,运行时中文乱码
比如以下代码: import javax.swing.*; public class addJarPkg { public static void main(String[] args) { JFra ...