boolean res1 = atomicReference.compareAndSet(100, 101);
boolean res2 = atomicReference.compareAndSet(101, 100);
System.out.println("res1=" + res1);
System.out.println("res2=" + res2);
}).start();
new Thread(() -> {
boolean res3 = atomicReference.compareAndSet(100, 200);
System.out.println("res3=" + res3);
}).start();
}
}
运行结果:res1,res2,res3都是true,这说明虽然线程t1修改了atomicReference中的值,但是由于修改后值与原来的一样,所以线程t2在判断的时候认为该值没有被修改过CAS操作成功。
AtomicStampedReference解决ABA问题
-----------------------------
为了解决ABA问题,引入了AtomicStampedReference,AtomicStampedReference它内部不仅维护了对象值,还维护了一个时间戳(版本号)。当AtomicStampedReference对应的数值被修改时,除了更新数据本身外,还必须要更新时间戳。
### AtomicStampedReference的构造器
在初始化的时候传入两个参数,初始化的引用值和版本号
public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}
### AtomicStampedReference的compareAndSet方法
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)));
}
* expectedReference : 期望值
* newReference : 想要更新成的新的值
* expectedStamp : 期望的版本号
* newStamp : CAS操作成功要更新成的版本号
**然后每次操作的时候都会先比较版本号,版本号一致才能操作成功,每次操作成功后都将版本号增加+1(版本号只加不减)**
### 测试代码
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;
public class ABASolve {
public static void main(String[] args) {
AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);
int stamp = atomicStampedReference.getStamp();
new Thread(() -> {
System.out.println("t1线程拿到的初始版本号:" + stamp);
System.out.println("t1线程拿到的初始值:" + atomicStampedReference.getReference());
//
boolean res1 = atomicStampedReference.compareAndSet(100, 101, stamp, atomicStampedReference.getStamp() + 1);
System.out.println("修改结果:" + res1);
System.out.println("t1线程修改之后的版本号:" + atomicStampedReference.getStamp());
System.out.println("t1线程修改之后的值:" + atomicStampedReference.getReference());
boolean res2 = atomicStampedReference.compareAndSet(101, 100, 2, atomicStampedReference.getStamp() + 1);
System.out.println("修改结果:" + res2);
}).start();
new Thread(() -> {
System.out.println("t2线程拿到的初始版本号:" + stamp);
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
boolean b1 = atomicStampedReference.compareAndSet(100, 101, stamp, atomicStampedReference.getStamp() + 1);
System.out.println("t2线程期望的版本号为" + stamp + ",t2线程当前查看主内存中atomicStampedReference真实的版本号为:" + atomicStampedReference.getStamp());
System.out.println("t2线程CAS操作的结果为:" + b1);
}).start();
}
}
该代码模拟了线程1将atomicStampedReference值修改后又改回成原来的值的过程,观察版本号的变化以及最后线程2的CAS操作成功与否,**运行结果如下:**
t1线程拿到的初始版本号:1
t1线程拿到的初始值:100
修改结果:true
t1线程修改之后的版本号:2
t1线程修改之后的值:101
修改结果:true
t2线程拿到的初始版本号:1
t2线程期望的版本号为1,t2线程当前查看主内存中atomicStampedReference真实的版本号为:3
t2线程CAS操作的结果为:false
总结
--
# 最后总结
搞定算法,面试字节再不怕,有需要文章中分享的这些**二叉树、链表、字符串、栈和队列等等各大面试高频知识点及解析**
**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](https://codechina.csdn.net/m0_60958482/java-p7)**
最后再分享一份**终极手撕架构的大礼包(学习笔记):分布式+微服务+开源框架+性能优化**
![image](https://img-blog.csdnimg.cn/img_convert/73c691eeb8b632cb7bc9b3bd81813b30.png)
链表、字符串、栈和队列等等各大面试高频知识点及解析**
**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](https://codechina.csdn.net/m0_60958482/java-p7)**
最后再分享一份**终极手撕架构的大礼包(学习笔记):分布式+微服务+开源框架+性能优化**
[外链图片转存中...(img-5XMsGzY4-1630718164769)]