synchronized 底层是如何实现的 ?

目录

1. synchronized 底层是如何实现的

2. 监视器的执行流程


1. synchronized 底层是如何实现的

synchronized 底层是通过 JVM 内置的 Monitor 监视器实现的。

以下代码,查看它运行时的字节码文件:

public class SynchronizedMonitorDemo {
    public static void main(String[] args) {
        int count = 0;
        synchronized (SynchronizedMonitorDemo.class) {
            for(int i = 0; i < 10; ++i) {
                count++;
            }
        }
        System.out.println(count);
    }
}

使用 IDEA 字节码插件 Bytecode Viewer 查看字节码文件: 

从字节中可以看到两个指令:

  • monitorenter:表示进入监视器
  • monitorexit:表示退出监视器

由此可知 synchronized 底层是依赖 Monitor 监视器来实现的。

2. 监视器的执行流程

        既然我们知道了 synchronized 的底层是依赖 Monitor 监视器来实现的,那么监视器它到底是怎么执行的呢 ?知其然还要知其所以然~

什么是监视器?

监视器它是一种机制,用来保障在任何时候,只有一个线程能够执行某个区域内的代码。

一个监视器可以看作是一栋房子,房子里有一个特殊的房间,这个房间同一时刻只能被一个线程所占有。占有该房间的线程可以共享该房间的所有数据。

进入该房子:进入监视器

进入该房间:获得监视器

离开该房间:释放监视器

离开该房子:退出监视器

在 hosSpot 虚拟机中,监视器底层是由 C++ 实现的,它的实现是一个结构体对象,它里面有以下几个重要属性:

  • _count:记录该线程获取锁的次数;
  • _recursions:记录锁的重入次数;
  • _owner:表示拥有监视器对象的线程;
  • _EntryList:表示监控集合,用于存放多线程情况下,竞争监视器失败的线程(处于阻塞状态的线程队列);
  • _WaitSet:表示待授权集合,用于存放进入 waiting 状态的线程队列(当线程调用了 wait() 方法就会进入该集合)。

具体执行流程参考下图>>

监视器

它的执行流程大致是这样的 >>

  1. 线程通过 CAS(compare and swap) 尝试获取锁,如果获取成功了,就将 _owner 字段设置给当前线程,表示当前线程持有监视器锁,并将 _recusions 重入次数 + 1;如果获取失败,则通过 CAS 自旋不断尝试获取锁,尝试一定次数还是失败,那么就加入到 EntrySet 监控集合中(阻塞)。
  2. 当持有监视器锁的线程调用了 wait() 方法,当前线程就会释放锁,并将 _owner 字段恢复为 null,同时将当前线程加入到 WaitSet 待授权集合中,等待被唤醒。
  3. 当调用 notify() 方法时,随机唤醒 WaitSet 待授权集合中的某一个线程,当调用 notifyAll() 方法时,唤醒 WaitSet 待授权集合中所有的线程尝试获取锁。
  4. 线程执行完释放锁后,唤醒 EntrySet 监控集合中的所有的线程尝试获取锁。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Master_hl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值