文章目录

  • 前言
  • 一、乐观锁和悲观锁
    • 1.1乐观锁
    • 1.2悲观锁
    • 1.3自旋锁
  • 二、CAS
    • 2.1什么是CAS?
    • 2.2ABA 问题
  • 总结

前言

Java中的锁主要用于保障线程在多并发情况下数据的一致性。锁从乐观和悲观的角度可分为乐观锁和悲观锁,JVM还巧妙的设计了自旋锁更快的使用CPU资源。


一、乐观锁和悲观锁

1.1乐观锁

乐观锁采用乐观的思想处理数据,即每次读取数据时都认为别人不会修改该数据,不会进行加锁。

JAVA中的乐观锁大部分是通过CAS操作实现的,CAS是一种原子更新操作,对数据操作之前会比较要更新的值和预期的值是否相同,如果相同才会进行更新,否则会再次尝试,直到成功。

1.2悲观锁

悲观锁采用悲观的思想处理数据,认为每次读取数据时别人都会修改数据,所以每次读写数据都会加锁,不允许别的线程同时操作。

JAVA中的悲观锁大部分基于AQS(抽象的队列同步器)实现。AQS定义了一套多线程访问共享资源的同步框架,许多同步类的实现都依赖它,例如:ReentranLock等。

1.3自旋锁

自旋锁( SpinLock),spin在英文中用于描述纺纱的纱轮疯狂自转的样子。认为如果持有锁的线程在很短的时间就会释放锁资源,那么等待的线程只需要等一等,重试不断的去尝试获取锁(自旋),不需要进入阻塞、挂起状态。

自旋锁的优点
1.非常适合占用锁时间非常短的场景,极大提高锁的效率,自旋等待的时间明显少于线程阻塞挂起和在唤醒所用的时间。

自旋锁缺点:
如果线程占用锁时间过长,线程在自旋的时候会长时间获取不到锁,造成CPU资源浪费。


二、CAS

2.1什么是CAS?

CAS 是乐观锁的一种实现方式,他采用的是自旋锁(一直尝试,直到成功)的思想,是一种轻量级的锁机制。

CAS(Compare And Swap)指比较并交换。CAS算法CAS(V,E,N)包含三个参数,V表示要更新的变量,E表示预期的值,N表示新值。仅在V值等于E值,才会将V值设为N,如果V值和E值不同,表示有其他线程进行更新,当前线程什么都不做,不会被挂起,允许再次尝试,直到成功

从JDK 1.5开始提供了java.util.concurrent.atomic包,在该包中提供了许多基于CAS实现的原子操作类,用法方便,性能高效。我们以AtomicInteger为例进行分析CAS的JAVA实现代码。

JDK1.7

 public class AtomicInteger extends Number implements java.io.Serializable {private volatile int value;public final int get() {return value;}//JDK 1.7的源码,由for的死循环实现,并且直接在AtomicInteger实现该方法,//JDK1.8后,直接调用getAndAddInt方法即可public final int getAndIncrement() {for(;;){              //CAS自旋,一直尝试,直到成功int current=get();int next=current+1;if(compareAndSet(current,next)){return current;}       }}public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}}

JDK1.8

//AtomicInteger中的方法public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset, 1);}//Unsafe中的方法public final int getAndAddInt(Object var1, long var2, int var4) {int var5;do {var5 = this.getIntVolatile(var1, var2);} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));return var5;}

CAS是采用了乐观锁的思想,总是认为自己可以成功完成操作。有多个线程同时使用CAS操作同一个变量时只有一个会成功更新,其余均会失败。

2.2ABA 问题

第一个线程从内存的V位置取出了A,第二个线程也从内存的V位置取出了A,先修改成B,然后又修改成了A,第一个线程在进行CAS操作时不会察觉到异常,虽然操作正常进行,但该数据已经发生过变化,某些应用场景下可能出现数据不一致的问题。

解决办法:添加版本号,执行操作时加上一个版本号,版本号一致性可以进行操作,否则失败。每次操作版本号增加,因为版本号只会增加不会减少,所以不会出现ABA问题。

例如:
1.线程1读取A(1)
2.线程2读取A(1),修改成B(2),又修改成A(3),
3.线程1读取预期值,发现预期值A(3)和变量值A(1)不同,不进行操作。


总结

除了本文提到的锁的类型,锁从获取资源的公平性角度可以分为公平锁和非公平锁,从是否共享资源的角度可分为共享锁和独占锁,从锁的状态可分为偏向锁、轻量级锁和重量级锁,后续会介绍这些锁的特性。本文的重点CAS,理解了CAS就理解了乐观锁和自旋锁的特点,对于比较并交换的过程一定要牢记于心。


CAS操作原理与实现相关推荐

  1. Java CAS底层原理

    Java CAS底层原理 Java CAS底层原理,这一篇就够了!!! CAS全称(Conmpare And Swap)比较并交换,是一种用于在多线程环境下实现同步功能的机制.CAS 操作包含三个操作 ...

  2. java对象头_我的并发编程(二):java对象头以及synchronized升级过程

    一.概述 研究java对象头的目的是详细分析Java的synchronized锁的升级过程,因为synchronized在锁升级的时候,就是依赖对象头的信息来决定的.本博文针对64位的操作系统来对Ja ...

  3. Java多线程 ——线程基础和锁锁锁

    Java多线程(一) 一.线程的定义 二.Synchronize线程同步 三.偏向锁.自旋锁.重量级锁 四.volatile关键字 4.1.普通变量运算的物理意义 4.2.有无解决的方案 4.3.vo ...

  4. 最全面java面试题集

    一.JavaSE 部分 基础部分 Java中基本数据类型有哪些? byte:8位,最大存储数据量是255,存放的数据范围是-128~127之间. short:16位, int:32位,最大数据存储容量 ...

  5. 乐观锁和悲观锁的原理及应用场景

    一.乐观锁和悲观锁的策略 1.悲观锁(一般都是通过锁机制来实现的) (1)每次去拿数据都会认为别人会修改,所以每次拿数据的时候都会上锁.比如:行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁.再比如 ...

  6. 找工作再也不愁之面试题全覆盖-Java基础篇

    一.JavaSE 部分 基础篇 Java中基本数据类型有哪些? byte:8位,最大存储是0-255,存放的数据范围是-128~127之间. short:16位,最[大数据]存储量是65536,数据范 ...

  7. Java并发编程进阶——多线程的安全与同步

    多线程的安全与同步 多线程的操作原则 多线程 AVO 原则 A:即 Atomic,原子性操作原则.对基本数据类型变量的读和写是保证原子性的,要么都成功,要么都失败,这些操作不可中断. V:即 vola ...

  8. java面试题大全必备神器

    Java面试题大全 一.JavaSE 部分 基础部分 Java中基本数据类型有哪些? byte:8位,最大存储数据量是255,存放的数据范围是-128~127之间. short:16位, int:32 ...

  9. 从底层吃透java内存模型(JMM)、volatile、CAS

    前言 随着计算机的飞速发展,cpu从单核到四核,八核.在2020年中国网民数预计将达到11亿人.这些数据都意味着,作为一名java程序员,必须要掌握多线程开发,谈及多线程,绕不开的是对JMM(Java ...

最新文章

  1. 华为最新系统鸿蒙的意思,EMUI官微正式更名为HarmonyOS!华为鸿蒙系统的推出有何意义?...
  2. [SDOI2011]染色
  3. win10家庭版没有device guard_普通用户选择哪个Win10系统版本?家庭版与专业版的对比介绍...
  4. 参数化测试 junit_使用JUnit 5进行更清洁的参数化测试
  5. 云计算如何使企业的业务受益?
  6. python爬取去哪网数据_python最强的代理池,突破IP的封锁爬取海量数据(送项目源码)...
  7. 软件测试的基础知识(六)
  8. ActiveMQ—Windows操作系统中如何安装启动ActiveMQ
  9. 微信支付可以在App Store购买应用了 附绑定教程
  10. excel 案例素材_盘点 | 十分钟进阶Excel数据可视化
  11. anaconda 安装Mosek
  12. Java 开发之微信(支付宝)扫码支付的小总结
  13. 三星android系统应用,三星Android系统文件夹全解
  14. java中wgs84转高德_2020-06-11关于WGS84 高德坐标 百度坐标的相互转换
  15. JAVA 编写一个员工类,成员变量和成员方法自拟,编写一个测试类
  16. 四级词汇4000快速记忆
  17. TouchDesigner学习 颜色控制模块
  18. 苹果暗黑模式_微信暗黑模式终于来了!这次微信对苹果认怂了?腾讯张军回应......
  19. ASP.NET 中验证的自定义返回和统一社会信用代码的内置验证实现
  20. 为什么 C++ 中成员函数指针是 16 字节?

热门文章

  1. MySQL 查询分析
  2. mysql查询数据库ppt_数据库与数据库服务器.ppt
  3. uniapp使用Vant-weapp(最新)
  4. vue服务器渲染/nuxt/vant-ui/mint-ui/typeScript/stylus(简单了解带网址)
  5. 彻底理解对象内存分配及Minor GC和Full GC全过程
  6. android绘制自定义室内地图,自定义样式-实用工具-开发指南-Android 室内地图SDK | 高德地图API...
  7. 100多个shell脚本的例子
  8. “Tranfer-Encodeing:chunked“和“Content-Length“这两个字段是互斥的理解
  9. 如何制作一份导航电子地图(上)
  10. 解决java配置文件存储汉字乱码问题