CAS

CAS:Compare and Swap, 翻译成比较并交换。

java.util.concurrent包中借助CAS实现了区别于synchronized同步锁的一种乐观锁。

其原理是CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

ABA问题

    private static AtomicInteger atomicInt = new AtomicInteger(100);
public static void main(String[] args) throws InterruptedException {
Thread intT1 = new Thread(new Runnable() {
@Override
public void run() {
atomicInt.compareAndSet(100, 101);
log("thread intT1:" + atomicInt.get());
atomicInt.compareAndSet(101, 100);
log("thread intT1:" + atomicInt.get());
}
}); Thread intT2 = new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean c3 = atomicInt.compareAndSet(100, 101);
log("thread intT2:" + atomicInt.get() + ",c3 is:" + c3); //true
}
}); intT1.start();
intT2.start();

上面程序的打印结果如下:

thread intT1:101
thread intT1:100
thread intT2:101,c3 is:true

线程intT2获取到的变量值A,尽管和当前的实际值相同,但内存地址V中的变量已经经历了A->B->A的改变。实际应用中有可能会导致漫画:什么是CAS机制?(进阶篇)中所提到的提款问题。

解决方案

JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。如果当前引用 == 预期引用,并且当前标志等于预期标志,则以原子方式将该引用和该标志的值设置为给定的更新值。源码如下:

/**
*expectedReference - 该引用的预期值
*newReference - 该引用的新值
*expectedStamp - 该标志的预期值
*newStamp - 该标志的新值
*/
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 static AtomicStampedReference<Integer> atomicStampedRef =
new AtomicStampedReference<Integer>(100, 0); Thread refT1 = new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicStampedRef.compareAndSet(100, 101,
atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
log("thread refT1:" + atomicStampedRef.getReference());
atomicStampedRef.compareAndSet(101, 100,
atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
log("thread refT1:" + atomicStampedRef.getReference());
}
}); Thread refT2 = new Thread(new Runnable() {
@Override
public void run() {
int stamp = atomicStampedRef.getStamp();
log("before sleep : stamp = " + stamp); // stamp = 0
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
log("after sleep : stamp = " + atomicStampedRef.getStamp());//stamp = 1
boolean c3 = atomicStampedRef.compareAndSet(100, 101, stamp, stamp + 1);
log("thread refT2:" + atomicStampedRef.getReference() + ",c3 is " + c3); //true
}
}); refT1.start();
refT2.start();
} private static void log(String logString) {
System.out.println(logString);
}

输出结果如下:

before sleep : stamp = 0
thread refT1:101
thread refT1:100
after sleep : stamp = 2
thread refT2:100,c3 is false

可以看到refT2的值和expect是相同的,但是由于版本号发生了变化,所以更新失败。

作者:时光之刃51y
链接:https://www.jianshu.com/p/8de8c6a839e8
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

最新文章

  1. pt-heartbeat
  2. ExtJs知识点概述
  3. PAT 1019. 数字黑洞 (20)
  4. 搭建wordpress开发环境
  5. library not found for -lPods 的解决办法
  6. Mentor PADS 9.5下载安装及破解指南
  7. Dojo Widget系统(转)
  8. WebSocket C# Demo
  9. SQL2008 &#39;OFFSET&#39; 附近有语法错误。 在 FETCH 语句中选项 NEXT 的用法无效。
  10. 转:【深入Java虚拟机】之五:多态性实现机制——静态分派与动态分派
  11. 记录一次参加D2前端技术论坛的杭州之行
  12. 浏览器抓包(post)
  13. [编织消息框架][netty源码分析]13 ByteBuf 实现类CompositeByteBuf职责与实现
  14. H3C单臂路由配置
  15. Linux下system()函数的实现
  16. 若要允许 GET 请求,请将 JsonRequestBehavior 设置为 AllowGet
  17. 从PHP官方镜像创建开发镜像
  18. HTTP.ResponseCode
  19. 2月9日 Time and Date(Ruby基础) \n 2月10日 ,使用Proc,block对象化。
  20. POJ1410_还是没考虑全面——线段是否与矩形有共同的垂直投影

热门文章

  1. File类与常用IO流第三章IO流概述
  2. 去掉返回的json中特殊字符
  3. 流畅的python--装饰器
  4. 第十二篇 -- 关于U盘制作启动盘后在本机上显示不出来的解决方案
  5. jvm源码解读--07 创建 fixup_mirrors
  6. windows10激活方法
  7. salesforce Integration 概览(一) 杂篇
  8. jquery 判断单/复选框是否被选中
  9. 如何在windows 11中安装WSLG(WSL2)
  10. Linux的磁盘管理和进程管理(入门)