Java多线程之CAS缺点


目录:

  1. 循环时间开销很大
  2. 只能保证一个共享变量的原子操作
  3. 引来ABA问题及解决方案(重点)

1. 循环时间开销很大


通过看源码,我们发现有个do while,如果CAS失败,会一直进行尝试。如果CAS长时间一直不成功,可能会给CPU带来很大的开销。


2. 只能保证一个共享变量的原子操作

当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作。但是,对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可用锁来保证原子性。


3. 引来ABA问题及解决方案(重点)


1.ABA问题概述

  1. CAS会导致"ABA问题”
  2. CAS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并替换,那么在这个时间差类会导致数据的变化。
  3. 比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且线程two进行了一些操作将值变成了B,然后线程two又将V位置的数据变成A,这时候线程One进行CAS作发现内存中仍然是A,然后线程One操作成功。
  4. 尽管线程One的CAS慢作成功,但是不代表这个过程就是没有问题的。

2. 原子引用

解决ABA问题只靠CAS不能解决,还需要用到原子引用技术。即AtomicReference

简单代码测试

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;import java.util.concurrent.atomic.AtomicReference;@Getter
@ToString
@AllArgsConstructor
class User{String userName;int age;
}
public class AtomicReferenceDemo {public static void main(String[] args) {User z3 = new User("Z3",22);User li4 = new User("li4",25);AtomicReference<User> atomicReference = new AtomicReference<>();atomicReference.set(z3);System.out.println(atomicReference.compareAndSet(z3, li4)+"\t"+atomicReference.get().toString());System.out.println(atomicReference.compareAndSet(z3, li4)+"\t"+atomicReference.get().toString());}
}

编译结果

3. ABA问题解决方案

解决: 原子引用+修改版本号(类似时间戳)

代码:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;/*** ABA问题的解决:  AtomicStampedReference*/
public class ABADemo {static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);public static void main(String[] args) {System.out.println("=============以下是ABA问题的产生==============");new Thread(() -> {atomicReference.compareAndSet(100, 101);atomicReference.compareAndSet(101, 100);}, "t1").start();new Thread(() -> {try {//暂停一秒钟,保证上面的t1完成了一次ABA操作TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(atomicReference.compareAndSet(100, 2019)+ "\t" + atomicReference.get());}, "t2").start();//暂停两秒钟等上面代码执行完try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("=============以下是ABA问题的解决==============");new Thread(() -> {int stamp = atomicStampedReference.getStamp();System.out.println(Thread.currentThread().getName() + "\t第一次版本号" + stamp);//            暂停一秒钟t3线程,为了t4线程也能拿到相同的stamp。try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}atomicStampedReference.compareAndSet(100, 101,atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);System.out.println(Thread.currentThread().getName() + "\t第2次版本号" + atomicStampedReference.getStamp());atomicStampedReference.compareAndSet(101, 100,atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);System.out.println(Thread.currentThread().getName() + "\t第2次版本号" + atomicStampedReference.getStamp());}, "t3").start();new Thread(() -> {int stamp = atomicStampedReference.getStamp();System.out.println(Thread.currentThread().getName() + "\t第一次版本号" + stamp);//            暂停3秒钟t4线程,保证上面的t3线程完成了一次ABA操作。try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}boolean result = atomicStampedReference.compareAndSet(100, 101, stamp, stamp + 1);System.out.println(Thread.currentThread().getName() + "\t修改成功否:" + result+ "\t当前最新实际版本号:" + atomicStampedReference.getStamp());System.out.println(Thread.currentThread().getName() + "\t当前实际最新值" + atomicStampedReference.getReference());}, "t4").start();}
}

编译结果:

Java多线程之CAS缺点相关推荐

  1. Java多线程之CAS深入解析

    Java多线程之CAS深入解析 目录: CAS是什么 CAS底层原理Unsafe深入解析 CAS缺点 引子:蚂蚁花呗一面:讲一讲AtomicInteger,为什么要用CAS而不是synchronize ...

  2. java中多线程之CAS(compareAndSet),Unsafe类大白话详解.

    java中多线程之CAS(compareAndSet),Unsafe类大白话详解 什么是CAS CAS原理 Unsafe类:     什么是CAS 比较并交换 在学习CAS之前,我们先了解一下JMM. ...

  3. Java并发编程之CAS第三篇-CAS的缺点

    Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...

  4. JAVA多线程之wait/notify

    本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...

  5. Java多线程之Callable、Future和FutureTask

    Java多线程之Callable接口 自己想总结一下的,看到一篇总结的更好的博客,就转载了,突然感觉真轻松,哈哈哈哈 文章转载于:Matrix海子:Java并发编程:Callable.Future和F ...

  6. Java多线程之Synchronized和Lock的区别

    Java多线程之Synchronized和Lock的区别 目录: 原始构成 使用方法 等待是否可以中断 加锁是否公平 锁绑定多个条件Condition 小结:Lock相比较Synchronized的优 ...

  7. Java多线程之volatile详解

    Java多线程之volatile详解 目录: 什么是volatile? JMM内存模型之可见性 volatile三大特性之一:保证可见性 volatile三大特性之二:不保证原子性 volatile三 ...

  8. Java多线程之Semaphore用法

    Java多线程之Semaphore用法 本文目录: Semaphore基本概念 Semaphore使用案例:3个停车位,6辆车去抢,走一辆,抢一个停车位. 1. Semaphore基本概念 在信号量上 ...

  9. Java多线程之CyclicBarrier用法

    Java多线程之CyclicBarrier用法 本文目录 CyclicBarrier的基本概念 CyclicBarrier的案例:集齐7颗龙珠就可以召唤神龙 1. CyclicBarrier的基本概念 ...

最新文章

  1. 技术详解 | 如何用GAN实现阴影检测和阴影去除?
  2. 关于 Session 的深入探讨
  3. 信息安全系统设计基础第一周学习总结
  4. SRS流媒体服务器——单机环境搭建和源码目录介绍
  5. python中span函数,如何用python中BeautifulSoup提取无类名的span内文本
  6. sql管理:索引超出范围必须为非负值并小于集合大小_java面试基础知识-数据库基础知识(数据库索引部分)...
  7. ERROR! The server quit without updating PID file (/usr/local/var/mysql/apple,卸载,重装一个,我的方案
  8. 【Kafka】报错:Error while fetching metadata with correlation id 1 : {topic_lcc=LEADER_NOT_AVAILABLE}
  9. Anaconda创建、激活、退出、删除虚拟环境
  10. nginx 认证访问web
  11. 在Docker和Kubernetes上运行MongoDB微服务
  12. shell脚本中变量的赋值
  13. transformClassesWithProfilers-transformForDebug
  14. 【ML小结2】信息论
  15. 手机麦克风结构原理图_做一个最会搞气氛的人,唱吧小巨蛋麦克风G2评测:明星同款...
  16. svg格式的中国地图轮廓图
  17. ugp和千幻魔镜买哪个好_2020年买VR盒子十大品牌推荐 VR手机盒子如何使用
  18. golang sync/atomic
  19. Linux 系统设置 : hwclock 命令详解
  20. 关于HTML中的滚动条

热门文章

  1. Spring 概念及特点 Spring下载地址 控制反转IoC实现原理
  2. 用BlazeMeter录制JMeter测试脚本
  3. 机器人语言特性探索2-正在发生的趋势
  4. jquery插件 --- 图表 表格
  5. dasblog的安装
  6. 开放源代码GIS资源集锦
  7. 鸿蒙系统发红包,鸿蒙修真录红包版
  8. linux算法设计,红黑树的原理分析和算法设计
  9. python各种数据类型的常用方法_python的基本数据类型:列表的方法
  10. 2021已去,2022未来