1
0

CAS.md 5.6 KB

什么是悲观锁?什么是乐观锁

悲观锁:

  1. 站在 mysql 的角度分析:悲观锁就是比较悲观,当多个线程对同一行数据实现修改的时候,最后只有一个线程才能修改成功,只要谁能够对获取到行锁则其他线程时不能够对该数据做任何修改操作,且是阻塞状态。 注意:mysql 的 innodb 引擎中存在行锁的概念
  2. 站在 java 锁层面,如果没有获取到锁,则会阻塞等待,后期唤醒的锁的成本就会非常高,重新被我们 cpu 从就绪调度为运行状态。 例如Lock syn 锁等,悲观锁没有获取到锁的线程会阻塞等待; image-20211031163542154

乐观锁:

乐观锁比较乐观,通过预值或者版本号比较,如果不一致性的情况则通过循环控制修改(不断循环查询版本号),当前线程不会被阻塞,是乐观,效率比较高,但是乐观锁比较消耗 cpu 的资源。 image-20211031163822733 乐观锁:获取锁----如果没有获取到锁,当前线程是不会阻塞等待,通过死循环控制。

Mysql 层面如何实现乐观锁呢

在我们表结构中,会新增一个字段就是版本字段 version varchar(255) DEFAULT NULL, 多个线程对同一行数据实现修改操作,提前查询当前最新的 version 版本号码,作为 update 条件查询,如果当前 version 版本号码发生了变化,则查询不到该数据。 表示如果修改数据失败,则不断重试 ,又重新查询最新的版本实现 update。 需要注意控制乐观锁循环的次数,避免 cpu 飙高的问题。 mysql 的 innodb 引擎中存在行锁的概念

JAVA乐观锁实现方式

基于CAS实现 原理: 变量=====0 0表示没有线程获取该锁; 1表示已经有线程获取到该锁; Cas获取锁: Cas修改变量值=0->1===Cas修改成功的话则表示获取锁成功 Cas释放锁 变量1->0 Cas释放锁成功

JAVA锁的分类

  1. 悲观(例如syn与lock)与乐观锁
  2. 公平锁与非公平锁
  3. 自旋锁/重入锁
  4. 重量级锁与轻量级锁
  5. 独占锁与共享锁

公平锁与非公平锁之间的区别

公平锁:就是比较公平,根据请求锁的顺序排列,先来请求的就先获取锁,后来获取锁就最后获取到, 采用队列存放 类似于吃饭排队。底层实现就是链表 非公平锁:不是据请求的顺序排列, 通过争抢的方式获取锁。非公平锁效率比公平锁效率要高,Synchronized 是非公平锁 New ReentramtLock()(true)---公平锁 New ReentramtLock()(false)---非公平锁 底层基于 aqs 实现

什么是锁的可重入性

在同一个线程中锁可以不断传递的,可以直接获取。

独占锁与共享锁之间的区别

独占锁:在多线程中,只允许有一个线程获取到锁,其他线程都会等待。 共享锁:多个线程可以同时持有锁,例如 ReentrantLock 读写锁。读读可以共享、写写互斥、读写互斥、写读互斥。

什么是 CAS(自旋锁)(乐观锁),它的优缺点

CAS:没有获取到锁的线程是不会阻塞的,通过循环控制一直不断的获取锁。

CAS: Compare and Swap,翻译成比较并交换。 执行函数 CAS(V,E, N) CAS 有 3 个操作数,内存值 V,旧的预期值 E(V的备份值),要修改的新值 N。当且仅当预期值 E 和内存值 V 相同时,将内存值 V 修改为 N,否则什么都不做。 image-20211031175057474

  1. Cas 是通过硬件指令,保证原子性,不能同时修改
  2. Java 是通过 unsafe jni 技术 原子类: AtomicBoolean,AtomicInteger,AtomicLong 等使用 CAS 实现。 优点:没有获取到锁的线程,会一直在用户态,不会阻塞,没有锁的线程会一直通过循环控制重试。 缺点:通过死循环控制,消耗 cpu 资源比较高,需要控制循次数,避免 cpu 飙高问题; Cas 本质的原理: 旧的预期值===v(共享变量中值),才会修改我们 v。

Cas 无锁机制原理:

  1. 定义一个锁的状态;
  2. 状态状态值=0 则表示没有线程获取到该锁;
  3. 状态状态值=1 则表示有线程已经持有该锁; 实现细节: CAS 获取锁: 将该锁的状态从 0 改为 1-----能够修改成功 cas 成功则表示获取锁成功 如果获取锁失败--修改失败,则不会阻塞而是通过循环(自旋来控制重试) CAS 释放锁: 将该锁的状态从 1 改为 0 如果能够改成功 cas 成功则表示释放锁成功。

CAS 如何解决 ABA 的问题

什么是ABA问题?

In multithreaded computing, the ABA problem occurs during synchronization, when a location is read twice, has the same value for both reads, and "value is the same" is used to indicate "nothing has changed". However, another thread can execute between the two reads and change the value, do other work, then change the value back, thus fooling the first thread into thinking "nothing has changed" even though the second thread did work that violates that assumption.

Cas 主要检查 内存值 V 与旧的预值值=E 是否一致,如果一致的情况下,则修改。 这时候会存在 ABA 的问题: 如果将原来的值 A,改为了 B,B又改为了A发现没有发生变化,实际上已经发生了变化, 所以存在 Aba 问题。 解决办法:通过版本号码,对每个变量更新的版本号码做+1 解决 aba 问题是否大:概念产生冲突,但是不影响结果,换一种方式 通过版本号码方式。