美文网首页
多线程锁之 Synchronized

多线程锁之 Synchronized

作者: 蓝色空间号 | 来源:发表于2021-09-02 16:22 被阅读0次

    Synchronized 基本语法

    synchronized 有三中方式加锁:

    1. 修饰实例方法,作用于当前实例加锁,进入同步方法前要获得当前实例的锁
    2. 修饰静态方法,作用于当前类对象加锁,进入同步方法前要获得当前类对象的锁
    3. 修饰代码块,需要指定加锁对象,对指定对象加锁,进入同步方法前要获得指定对象的锁

    锁对象

    Synchronized 也被叫做对象锁,锁的标识是存储在对象头中的 MarkWord 中的。

    对象在内存中的结构
    image
    对象头中存储的信息
    image

    锁状态

    偏向锁
    说明:大部分情况下锁仅仅是由一个线程获取的,为了让线程获取锁的代价更低就引入了偏向锁,
         偏向锁持有某个线程ID,该线程再次进入和退出同步代码块时就不用获取和释放锁了。
    
    实现:在锁对象的对象头的 MarkWord 中存储持 线程ID和偏向锁的标识
    
    轻量级锁(自旋锁)
    说明:当线程发生锁竞争的情况后,因为偏向锁是不会释放锁的,所以偏向锁要立即升级到轻量级锁。
         对于轻量级锁线程是可以通过CAS自旋的方式进行锁的竞争
    
    实现:
        1. 在线程自己的栈桢中创建 锁记录 LockRecord
        2. 将锁对象中的MarkWord复制到 LockRecord中
        3. 将 LockRecord 中的 Owner 指向锁对象
        4. 将锁对象中的 MarkWord 替换为指向锁记录的指针
    
    重量级锁
    说明:未获取到锁的线程将会被阻塞,线程会被挂起,进入 Linux 内核。
         获取锁和释放锁都需要在 Linux 内核和用户内核之间进行切换,严重影响锁的性能。
    
    实现:每个对象都会与一个 monitor 监视器关联,由JVM实现。
    

    锁升级的过程

    1. 获取锁对象的 MarkWord,判断是否处于可偏向状态(biased_lock = 1 且 threadId 为空)

    2. 如果锁是可偏向状态,则通过 CAS 获取锁(尝试把当前线程ID 写入 MarkWord)

      • CAS成功:表明该线程获取到锁了,执行同步代码
      • CAS失败:表明其他线程抢先获取到了锁,这时产生了锁竞争的情况,这时需要撤销偏向锁,将锁升级到轻量级锁(这个操作需要等到全局安全点执行,即没有线程在执行字节码的时候),未获取到锁的线程会进行自旋+CAS 的方式获取锁,在一定次数的尝试获取后
        • 成功获取到锁:锁还是维持轻量级锁
        • 未获取到锁:升级到重量级锁(说明线程在执行同步代码的时候需要很多时间,因为自旋的时候是需要消耗CPU资源的,所以一旦自旋次数超过一定阈值,还未获取到锁,则说明锁需要升级到重量级锁)
    3. 如果锁已经是偏向状态,判断 MarkWord 中的线程ID是否等于当前线程的ID

      • 相等:则不用再次获取锁,可以直接执行同步代码
      • 不相等:同第2步的 “CAS失败”

    wait、notify 实现原理

    image

    相关文章

      网友评论

          本文标题:多线程锁之 Synchronized

          本文链接:https://www.haomeiwen.com/subject/lffkrctx.html