一. CAS

何为CAS。

CAS(Compare And Swap )是乐观锁的一种实现方式,是一种轻量级锁。JAVA1.5开始引入了CAS,JUC下很多工具类都是基于CAS。

CAS的实现方式

CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。当多个线程同时尝试使用CAS更新一个变量时,任何时候只有一个线程可以更新成功,若更新失败,线程会重新进入循环再次进行尝试。

CAS在Java中的应用

前面也说了JUC下面很多工具类都用到了CAS。其主要依赖于Unsafe的CAS操作来进行实现。
例如AtomicInteger下的incrementAndGet操作:

接着来看看Unsafe下的getAndAddInt方法

可以看到Unsafe中在循环体内先读取内存中的value值,然后CAS更新,如果CAS更新成功则退出,如果更新失败,则循环重试直到更新成功。

CAS带来的问题

ABA问题

例如说:
一. 线程1查询值是否为A
二. 线程2查询值是否为A
三. 线程2使用CAS将值更新为B
四. 线程2查询值是否为B
五. 线程2使用CAS将值更新为A
六. 线程1使用CAS将值更新为C
线程一线程二交替执行。第二步到第五步,线程二将值由A更新为B由更新为A,但线程一并没有察觉,因此线程一还是可以继续执行。我们称这种现象为ABA问题。
解决方法:
使用版本号 (时间戳),在每次在执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号加一,否则就执行失败。例如AtomicStampedReference就是通过对值加一个戳(stamp)来解决“ABA”问题的。

循环开销过大

CAS操作不成功的话,会导致一直自旋,CPU的压力会很大。例如说Unsafe下的getAndAddInt方法会一直循环,直到成功才会返回。

只能保证一个变量的原子操作

二. synchronized

相比于CAS基于乐观锁实现,synchronized是基于悲观锁的,当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。

对于普通同步方法加锁时,锁是当前实例对象。

对于静态同步方法加锁时,锁是当前类的Class对象。

对于同步方法块加锁时,锁是Synchonized括号里配置的对象。

Synchronized的实现方式:
Synchonized是基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。Synchronized 用在方法上时,在字节码中是通过方法的 ACC_SYNCHRONIZED 标志来实现的。而代码块同步则是使用monitorenter和monitorexit指令实现的。
monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处,JVM要保证每个monitorenter必须有对应的monitorexit与之配对。任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁,当获得对象的monitor以后,monitor内部的计数器就会自增(初始为0),当同一个线程再次获得monitor的时候,计数器会再次自增。当同一个线程执行monitorexit指令的时候,计数器会进行自减,当计数器为0的时候,monitor就会被释放,其他线程便可以获得monitor。

Synchronized的优化
Java SE 1.6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”,在Java SE 1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态。

偏向锁
当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。如果测试成功,表示线程已经获得了锁。如果测试失败,则需要再测试一下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁),如果没有设置,则使用CAS竞争锁;如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。

轻量级锁
线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。

重量级锁
重量级锁是依赖对象内部的monitor锁来实现。当系统检查到锁是重量级锁之后,会把等待想要获得锁的线程进行阻塞,被阻塞的线程不会消耗cup。但是阻塞或者唤醒一个线程时,都需要操作系统来帮忙,需要从用户态转换到内核态,而转换状态是需要消耗很多时间。

CAS和Synchronized知识相关推荐

  1. java基础-CAS、synchronized和AQS的理解

    乐观锁与悲观锁的区别? 悲观锁 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程 ...

  2. java让线程空转_Java锁:悲观/乐观/阻塞/自旋/公平锁/闭锁,锁消除CAS及synchronized的三种锁级别...

    JAVA LOCK 大全 [TOC] 一.广义分类:乐观锁/悲观锁 1.1 乐观锁的实现CAS (Compare and Swap) 乐观锁适合低并发的情况,在高并发的情况下由于自旋,性能甚至可能悲观 ...

  3. 1202年最新最详细最全的synchronized知识详解

    synchronized详解 前言 通俗:造成线程安全问题的主要诱因有两点: 存在共享数据(也称临界资源) 存在多条线程共同操作共享数据 学术:造成线程安全问题的主要诱因有两点: 主内存和线程的工作内 ...

  4. 【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 - 笔记

    引入 CAS lock cmpxchg在硬件层面实现:在操作过程中不允许被其他CPU打断,避免CAS在写数据的时候被其他线程打断,相比操作系统级别的锁,效率要高很多. 加锁才能让多线程的访问变为序列化 ...

  5. 使用CAS代替synchronized

    在开发当中需要经常用到synchronized保证代码线程安全,在竞争条件下会阻塞等待资源,如果允许竞争不到资源返回失败,就可以使用cas减少阻塞时间.先来看一个cas的单例模式. public cl ...

  6. 锁,CAS,Synchronized 原理

    作者:~小明学编程 文章专栏:JavaEE 格言:热爱编程的,终将被编程所厚爱. 目录 常见的锁 悲观锁与乐观锁 悲观锁 乐观锁 读写锁 重量级锁 vs 轻量级锁 挂起等待锁和自旋锁 公平锁和非公平锁 ...

  7. 锁策略、CAS、synchronized原理

    1.常见的锁策略 (1)乐观锁 和 悲观锁 乐观锁:预测锁竞争的情况不激烈(工作量较少) 悲观锁:预测锁竞争的情况很激烈(工作量较多) (2)轻量级锁 和 重量级锁 轻量级锁:加锁和解锁的开销较小,效 ...

  8. CAS(比较并交换)学习CAS实现原子性+volatile实现可见性,cas与synchronized比较的优缺点

    1.CAS底层原理? 自旋锁(cas思想)+unsafe类,保证原子性靠的是unsafe类 1.首先可以看到: atomicInteger.getAndIncrement(); getAndIncre ...

  9. Java并发(4)- synchronized与CAS

    引言 上一篇文章中我们说过,volatile通过lock指令保证了可见性.有序性以及"部分"原子性.但在大部分并发问题中,都需要保证操作的原子性,volatile并不具有该功能,这 ...

最新文章

  1. Kafka与RabbitMQ
  2. 卡尔曼滤波器学习笔记(一)
  3. markdown如何设置图片大小_Gitee(码云)实现免费 Markdown 图床
  4. ffmpeg 音乐循环_[宜配屋]听图阁
  5. python开发-常见面试题
  6. (21)npm scripts 实现自动化构建的最简方式
  7. 淡定的写代码,淡定的人生
  8. JQuery 表格拖动调整列宽效果
  9. 天锐绿盾技术大讲堂:解密审批流程管理
  10. AI智能中的OCR 少数民族文字识别-维吾尔文字识别
  11. Win10保护眼睛豆沙绿背景
  12. openwrt 遇到问题三 高通9531编译过程
  13. 细说大话西游中的经典元素
  14. 强对偶性、弱对偶性以及KKT条件的证明(对偶问题的几何证明)
  15. spring boot学习2,日志框架
  16. 怎么找计算机驱动程序不正常怎么办,网卡驱动程序不正常怎么办,教您解决电脑网卡驱动程序不正常...
  17. Android adb: failed to install 0.apk: Failure [null]
  18. 第1节 MySQL 架构篇 2021-12-24
  19. MODBUS报文负数优化处理代码(补码,反码) java
  20. 深度残差网络RESNET

热门文章

  1. lnmp解析php,搭建LNMP,可以解析PHP文件-Go语言中文社区
  2. md5不是对称密码算法_密码学中的消息摘要算法5(MD5)
  3. 汉子编码比字母编码长_字母/博客作者编码问题(使用动态编程)
  4. python 补前导零_Python正则表达式| 程序从IP地址中删除前导零
  5. sql服务器默认密码_搭建一个DNS服务器,轻松实现域名解析内容分发,访问速度提高N倍...
  6. lnmp构架——对tomcat详解
  7. JavaScript中的If和Else语句(香草)
  8. 一文汇总 JDK 5 到 JDK 15 中的牛逼功能!
  9. Visual Studio扩展工具添加与卸载
  10. pictureBox1.Image的获得图片路径的三种方法