Java的Synchronzied关键字

写作时间:2018.07.08
最后更新时间:2018.07.08

public class Sync {

    private static Object lock = new Object();

    public static void main(String[] args) {
        int i = 0;
        while (i++ < 100000) {
            doSomething();
        }
    }
    
    public static void doSomething() {
        int a = 0;
        synchronized (lock) {
            a++;
        }
    }
}

使用参数-XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly编译运行之后,可以看到如下信息:

  0x00007f6cbcce3385: jne     0x7f6cbcce33e4    ;*monitorenter
                                                ; - Sync::doSomething@7 (line 14)

  0x00007f6cbcce338b: lea     0x20(%rsp),%rax
  0x00007f6cbcce3390: mov     0x8(%rax),%rdi
  0x00007f6cbcce3394: mov     (%rdi),%rsi
  0x00007f6cbcce3397: and     $0x7,%rsi
  0x00007f6cbcce339b: cmp     $0x5,%rsi
  0x00007f6cbcce339f: je      0x7f6cbcce33bc
  0x00007f6cbcce33a5: mov     (%rax),%rsi
  0x00007f6cbcce33a8: test    %rsi,%rsi
  0x00007f6cbcce33ab: je      0x7f6cbcce33bc
  0x00007f6cbcce33b1: lock cmpxchg %rsi,(%rdi)
  0x00007f6cbcce33b6: jne     0x7f6cbcce33f4    ;*monitorexit
                                                ; - Sync::doSomething@12 (line 16)

可见,在Java中,synchronzied关键字是使用字节码monitorenter和moniterexit来实现的。monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处, JVM要保证每个monitorenter必须有对应的monitorexit与之配对。任何对象都有一个 monitor 与之关联,当且一个monitor 被持有后,它将处于锁定状态。线程执行到 monitorenter 指令时,将会尝试获取对象所对应的 monitor 的所有权,即尝试获得对象的锁。
那么这个所谓的锁在哪呢?
在Hotspot中,对象在内存中存储的布局可以分为3块:对象头,实例数据和为了对齐而做的填充。
对象的锁就保存在对象头的第一个字Mark Word中,在一个64位的虚拟机中,Mark Word就是64位长的,其中有3位和锁有关系,1位表示是否是偏向锁,2位表示锁状态,共有无锁定,轻量级锁定,重量级锁定3种状态。monitorenter和monitorexit就是通过操纵这3位来实现的。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容