转载

大白话聊聊synchronized、CAS底层原理、Lock锁和锁升级原理

目录

               1、乐观锁和悲观锁的概念

               2、synchronized底层的原理

               3.  CAS的原理

               4.  并发包下Lock锁和synchronized对比

               5.  锁升级原理
复制代码

大家好,我是四九城最豪横的小耳朵。

大白话聊聊synchronized、CAS底层原理、Lock锁和锁升级原理

今天咱们来用大白话聊聊synchronized、CAS底层原理、Lock锁和锁升级原理。

1、乐观锁和悲观锁的概念

比如线程A对某个变量进行修改,在这个修改期间,它持悲观心理,认为其他线程在这个期间,也有可能去修改这个变量,所以它就给变量加个锁,保证在它修改期间,别的线程没法去访问这个变量。这个锁就是悲观锁。悲观锁是重量级锁,代表对象synchronized关键字。

比如线程A对某个变量进行修改,在这个修改期间,它持乐观心理,认为其他线程在这个期间,不会去修改这个变量,所以它只在执行修改操作的时候,才会给变量加个锁。这个锁就是乐观锁。乐观锁是轻量级锁,代表对象CAS。

2、synchronized底层的原理

首先需要知道一个概念——monitor。

每个对象内部都有一个monitor,monitor里面有一个计数器,从0开始的。

大白话聊聊synchronized、CAS底层原理、Lock锁和锁升级原理

如果这个线程想获取monitor的锁,就先判断monitor的计数器是不是为0,如果为0,说明没人获取锁,这个线程就可以获取锁,然后对计数器加1;如果不为0,说明已经有其他线程已经获取了锁,这个线程就必须阻塞等待。

大白话聊聊synchronized、CAS底层原理、Lock锁和锁升级原理

synchronized底层的原理是跟jvm指令和monitor有关系的。

synchronized一般是对对象加锁,对类加锁也就是对类对象加锁。 如果使用了synchronized关键字,在底层编译后的jvm指令中, 会有monitorenter和monitorexit两个指令。线程进入synchronized代码片段,执行monitorenter指令对monitor计数器加1,这样其他线程发现monitor的计数器不为0,就阻塞等待;

大白话聊聊synchronized、CAS底层原理、Lock锁和锁升级原理

线程出synchronized代码片段,执行monitorexit指令就是对monitor计数器减1,这样其他线程发现monitor的计数器为0,就可以拿到锁,给monitor的计数器加1,然后执行业务逻辑了。

大白话聊聊synchronized、CAS底层原理、Lock锁和锁升级原理

上面的是针对synchronized对对象、类加锁的底层原理。

方法加锁不是通过monitor指令,而是通过ACC_SYNCHORNIZED关键字,判断方法是否同步。

3. CAS的原理

CAS,Conmpare And Swap,英文翻译过来就是“比较和交换”。它的过程是3步,第一步是读值,第二步比较值,看值和自己刚刚读的一不一样,第3步是修改,如果值跟自己读的一样,就修改。

CAS最经典的实现类就是AtomicInteger。

比如2个线程同时要对AtomicInteger加1,A线程读旧值,是0,B线程也读旧值,是0,A这时执行CAS操作,比较值,发现值和刚刚自己读的一样,都是0,然后它修改值为1;B线程执行CAS操作,比较值,发现值和刚刚自己读的不一样,变成1了,它相当于又读了一遍旧值,将自己内存中的旧值改为1,然后继续执行CAS操作。

CAS在底层的硬件级别给你保证一定是原子的,同一时间只有一个线程可以执行CAS,先比较再设置,其他的线程的CAS同时间去执行此时会失败。

CAS的bug是会出现的问题 ABA 空循环。如果要解决ABA 问题,可以使用AtomicStampedReference类, 它内部用类似创建版本号的方式来解决 ABA 问题。

4. 并发包下Lock锁和Synchronized对比

大白话聊聊synchronized、CAS底层原理、Lock锁和锁升级原理

我觉得二者的主要区别是以下四点;

1.首先synchronized是java内置关键字,是jvm层面,Lock是个java类,是jdk层面;

2.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;

3.synchronized会自动释放锁,Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;

4.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

5. 锁升级原理

一开始是无锁的状态,一上来会先去判断一下有没有锁,有锁的话最开始的时候锁是支持偏向锁的。偏向锁当前获取到锁资源的这个线程,我会优先让他再去获取这个锁,如果它没获取到这个锁,就升级为一个轻量级的,一个cas锁,即乐观锁,乐观锁的时候它是一个比较和交换的过程,如果没有设置成功的话,它会进行一个自旋,然后自旋到一定次数之后才会升级成一个synchronized的这样一个重量级的锁,这样的话他就保证了性能的问题。你想想如果一开始就是synchronized这样一个重量级的锁,那性能就比较差了。

大白话聊聊synchronized、CAS底层原理、Lock锁和锁升级原理
End
复制代码

作者简介:豪横的小耳朵,一个豪横的程序员。想和大家一起在技术的世界里豪横,用技术的眼光去看待世界。欢迎扫描下方二维码,持续关注,一大波原创系列文章正在路上

大白话聊聊synchronized、CAS底层原理、Lock锁和锁升级原理
原文  https://juejin.im/post/5e685ba7f265da57685dd3f7
正文到此结束
Loading...