synchronized 关键字底层原理属于 JVM 层⾯。

1. synchronized 同步语句块的情况

public class SynchronizedDemo {
    public void method() {
        synchronized(this) {
            System.out.println("synchronized 代码块");
        }
    }
}

通过 JDK ⾃带的javap命令查看SynchronizedDemo类的相关字节码信息:⾸先切换到类的对应⽬录执⾏javac SynchronizedDemo.java命令⽣成编译后的.class⽂件,然后执⾏javap -c -s -v -l SynchronizedDemo.class

file

从上⾯我们可以看出:
synchronized同步语句块的实现使⽤的是monitorentermonitorexit指令,其中monitorenter指令指向同步代码块的开始位置,monitorexit指令则指明同步代码块的结束位置。

当执⾏monitorenter指令时,线程试图获取锁也就是获取对象监视器monitor的持有权。

在 Java 虚拟机(HotSpot)中,Monitor 是基于 C++ 实现的,由ObjectMonitor实现的。每个对象中都内置了⼀个 ObjectMonitor 对象。
另外,wait/notify等⽅法也依赖于monitor对象,这就是为什么只有在同步的块或者⽅法中才能调⽤wait/notify等⽅法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

在执⾏monitorenter时,会尝试获取对象的锁,如果锁的计数器为 0 则表示锁可以被获取,获取后将锁计数器设为 1 也就是加 1。

在执⾏monitorexit指令后,将锁计数器设为 0,表明锁被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外⼀个线程释放为⽌。

2. synchronized 修饰⽅法的的情况

public class SynchronizedDemo2 {
    public synchronized void method() {
        System.out.println("synchronized ⽅法");
    }
}

file

synchronized修饰的⽅法并没有monitorenter指令和monitorexit指令,取得代之的确实是ACC_SYNCHRONIZED标识,该标识指明了该⽅法是⼀个同步⽅法。JVM 通过该ACC_SYNCHRONIZED访问标志来辨别⼀个⽅法是否声明为同步⽅法,从⽽执⾏相应的同步调⽤。

3. 总结

synchronized同步语句块的实现使⽤的是monitorentermonitorexit指令,其中monitorenter指令指向同步代码块的开始位置,monitorexit指令则指明同步代码块的结束位置。

synchronized修饰的⽅法并没有monitorenter指令和monitorexit指令,取得代之的确实是ACC_SYNCHRONIZED标识,该标识指明了该⽅法是⼀个同步⽅法。

不过两者的本质都是对对象监视器·monitor·的获取。

最后修改日期: 2021年11月28日

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。