带你深入剖析 synchronized 的底层原理
Posted 南淮北安
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带你深入剖析 synchronized 的底层原理相关的知识,希望对你有一定的参考价值。
文章目录
一、synchronized 的基本用法
可参考:一篇文章带你搞定 Java 中同步概念
可参考:一篇文章带你深入了解多线程中的线程组,守护线程,线程优先级,synchronize
synchronized 与 volatile 的最大区别在于原子性,volatile 不具备原子性
可参考:一篇文章带你深入了解 volatile 与 Java 内存模型(JMM)- 原子性、可见性、有序性
二、synchronized 的底层实现原理
1. 同步块的底层原理分析
public class SynchronizedDemo
public void method()
synchronized (this)
System.out.println("Method 1 start");
反编译:
生成class 文件:
javac SynchronizedDemo.java
反编译:javap -verbose SynchronizedDemo
每个对象都有一个监视器锁(monitor),synchronized 关键字经过编译之后,会在同步块的前后分别形成 monitorenter 和 monitorexit 两个字节码文件,执行 monitorenter 指令时,首先要尝试获取对象的锁,如果对象没被锁定,或者当前线程已经拥有了那个对象的锁,则把锁的计数器加1,相应的在执行 monitorexit 指令时,会将锁的计数器减1,当计数器为 0 时,锁就被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到对象锁被另外一个线程释放为止。
但是为什么会有两个monitorexit呢?
其实第二个monitorexit是来处理异常的,仔细看反编译的字节码,正常情况下第一个 monitorexit 之后会执行 goto 指令,而该指令转向的就是22行的return,也就是说正常情况下只会执行第一个 monitorexit 释放锁,然后返回。而如果在执行中发生了异常,第二个 monitorexit 就起作用了,它是由编译器自动生成的,在发生异常时处理异常然后释放掉锁。
所以,Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify
等方法也依赖于 monitor 对象,这就是为什么只有在同步的块或者方法中才能调用 wait/notify
等方法,否则会抛出java.lang.IllegalMonitorStateException
的异常的原因。
关于 wait/notify
可参考:一篇文章带你深入了解 Java 中线程的基本操作
2. 同步方法的底层原理分析
public class SynchronizedMethod
public synchronized void method()
System.out.println("SynchronizedMethod");
反编译分析:
javac SynchronizedMethod.java
javap -verbose SynchronizedMethod
从反编译的结果来看,方法的同步并没有通过指令 monitorenter 和 monitorexit 来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法,其常量池中多了ACC_SYNCHRONIZED
标示符。JVM就是根据该标示符来实现方法的同步的:当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED
访问标志是否被设置,如果设置了,执行线程将先获取 monitor,获取成功之后才能执行方法体,方法执行完后再释放 monitor。在方法执行期间,其他任何线程都无法再获得同一个 monitor 对象。 其实本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成。
四、总结
锁也分不同状态,JDK6之前只有两个状态:无锁、有锁(重量级锁),而在JDK6之后对synchronized进行了优化,新增了两种状态,总共就是四个状态:无锁状态、偏向锁、轻量级锁、重量级锁,其中无锁就是一种状态了。
锁的类型和状态在对象头Mark Word中都有记录,在申请锁、锁升级等过程中JVM都需要读取对象的Mark Word数据。
每一个锁都对应一个monitor对象,在HotSpot虚拟机中它是由ObjectMonitor实现的(C++实现)。每个对象都存在着一个monitor与之关联,对象与其monitor之间的关系有存在多种实现方式,如monitor可以与对象一起创建销毁或当线程试图获取对象锁时自动生成,但当一个monitor被某个线程持有后,它便处于锁定状态
对象头相关内容可参考:一篇带你探索 HotSpot虚拟机在Java堆中对象分配、布局和访问的全过程
synchronized 锁优化相关可参考:一篇文章带你搞定 JVM 中的锁优化
以上是关于带你深入剖析 synchronized 的底层原理的主要内容,如果未能解决你的问题,请参考以下文章
并发复习 ---- Synchronized底层原理深入分析
深入HotSpot虚拟机源码探究synchronized底层实现原理万字总结synchronized