Java锁——从字节码分析synchronized及monitor

1. synchronized同步代码块
m1方法代码

public void m1(){ synchronized (object){ System.out.println("----------hello sync"); } }

m1方法字节码
Java锁——从字节码分析synchronized及monitor
文章图片

synchronized实现使用的是monitorenter和monitorexit指令
一般情况下,monitorenter :monitorexit = 1:2,monitorexit: 1 正常完成 monitorexit: 2 保证异常over
m2方法代码
public void m2(){ synchronized (object){ System.out.println("----------hello sync"); throw new RuntimeException("----exception"); } }

m2方法字节码
Java锁——从字节码分析synchronized及monitor
文章图片
直接在里面抛异常,monitorenter :monitorexit = 1:1

2. synchronized普通同步方法
m3方法代码
public synchronizedvoid m3(){}

m3方法字节码
Java锁——从字节码分析synchronized及monitor
文章图片

Java锁——从字节码分析synchronized及monitor
文章图片

普通的同步方法(对象锁): 调用指令将会检查方法的ACC__SYNCHRONIZED访问标志是否被设置。如果设置了,执行线程会将先持有monitor然后再执行方法,最后在方法完成(无论是正常完成还是非正常完成)时释放monitor
3. synchronized静态同步方法
m4方法代码
public static synchronized void m4(){}

m4方法字节码
Java锁——从字节码分析synchronized及monitor
文章图片


Java锁——从字节码分析synchronized及monitor
文章图片

静态的同步方法(类锁): ACC_STATIC, ACC_SYNCHRONIZED访问标志区分该方法是否静态同步方法
4. 管程monitor
概念
管程 (Monitors,也称为监视器) 是一种程序结构,结构内的多个子程序(对象或模块)形成的多个工作线程互斥访问共享资源。
这些共享资源一般是硬件设备或一群变量。对共享变量能够进行的所有操作集中在一个模块中。(把信号量及其操作原语“封装”在一个对象内部)管程实现了在一个时间点,最多只有一个线程在执行管程的某个子程序。管程提供了一种机制,管程可以看做一个软件模块,它是将共享的变量和对于这些共享变量的操作封装起来,形成一个具有一定接口的功能模块,进程可以调用管程来实现进程级别的并发控制。
使用
方法级的同步是隐式的,无须通过字节码指令来控制,它实现在方法调用和返回操作之中。虛拟机可以从方法常量池中的方法表结构中的ACC_ SYNCHRONIZED访问标志得知一个方法是否被声明为同步方法。当方法调用时,调用指令将会检查方法的ACC_ SYNCHRONIZED访问标志是否被设置,如果设置了,执行线程就要求先成功持有管程,然后才能执行方法,最后当方法完成(无论是正常完成还是非正常完成)时释放管程。在方法执行期间,执行线程持有了管程,其他任何线程都无法再获取到同一个管程。如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那这个同步方法所持有的管程将在异常抛到同步方法边界之外时自动释放。
为什么任何一个对象都可以成为一个锁?
HotSpot虚拟机中,monitor采用ObjectMointor实现
【Java锁——从字节码分析synchronized及monitor】ObjectMonitor.java(Object类是所有类的祖先类)-> ObjectMonitor.cpp -> objectMonitor.hpp(每一个都有语义规定的hpp) 解读C++源码,每个对象天生都带一个对象监视器

    推荐阅读