通常 Synchronized 实现同步锁的方式有两种,一种是修饰方法,一种是修饰方法块。
通过反编译看下具体字节码的实现,运行以下反编译命令,就可以输出我们想要的字节码:
javap -v SyncTest.class // 再通过 javap 打印出字节文件
通过输出的字节码,你会发现:Synchronized 在修饰同步代码块时,是由 monitorenter 和 monitorexit
指令来实现同步的。进入 monitorenter 指令后,线程将持有 Monitor 对 象,退出 monitorenter
指令后,线程将释放该 Monitor 对象。当 Synchronized 修饰同步方法时,并没有发现 monitorenter 和 monitorexit 指令,而是出现了一个
ACC_SYNCHRONIZED 标志。这是因为 JVM 使用了 ACC_SYNCHRONIZED 访问标志来区分一个方法是否是同步方法。
当方法调用时,调用指令将会检查该方法是否被设置 ACC_SYNCHRONIZED 访问标志。
如果设置了该标志,执行线程将先持有 Monitor 对象,然后再执行方法。在该方法运行期间,其它线程将无法获取到该 Mointor
对象,当方法执行完成后,再释放该 Monitor 对象。JVM 中的同步是基于进入和退出管程(Monitor)对象实现的。每个对象实例都会有一个Monitor,Monitor
可以和对象一起创建、销毁。Monitor 是由 ObjectMonitor 实现当多个线程同时访问一段同步代码时,多个线程会先被存放在 EntryList 集合中,处于block
状态的线程,都会被加入到该列表。接下来当线程获取到对象的 Monitor 时,Monitor 是依靠底层操作系统的 Mutex Lock
来实现互斥的,线程申请 Mutex 成功,则持有该 Mutex,其它线程将无法获取到该 Mutex。如果线程调用 wait() 方法,就会释放当前持有的 Mutex,并且该线程会进入 WaitSet
集合中,等待下一次被唤醒。如果当前线程顺利执行完方法,也将释放 Mutex。同步锁在这种实现方式中,因 Monitor 是依赖于底层的操作系统实现,存在用户态与内核态之间的切换,所以增加了性能开销。
Synchronized 同步锁实现原理
最新推荐文章于 2024-02-28 17:17:56 发布