1

1.idea查看字节码jclasslib插件安装

2.从字节码角度分析synchronized实现

3.总结

1.idea查看字节码jclasslib插件安装
synchronize这个关键字我们肯定已经不陌生了,接下来我们从字节码这个角度来进行剖析一下,它为什么会有加锁的效果。我们先安装一下jclasslib插件,方便我们查看java的字节码。

image.png

点击view --> show Bytecode With Jclasslib
image.png

就可以看到这个文件的字节码啦。

image.png

2.从字节码角度分析synchronized实现

2.1synchronized同步代码块

public class LockByteDemo {
    final Object object = new Object();

    public void m1() {
        synchronized (object) {
            System.out.println("-------------hello sync");
            //throw new RuntimeException("6");
        }
    }
}

我们对m1()这个synchronized同步代码块方法进行查看一下字节码。

image.png

我们发现,它使用的是monitorenter指令monitorexit指令

monitor:
其实每一个对象都有一个monitor,就是监视器,当线程获取monitor成功的时候,这个对象就被锁住了。

monitorenter指令:
线程执行monitorenter就是为了尝试获取monitor的拥有权,过程为:

1)如果一个monitor的数值是0,那么线程直接进入monitor,并且将monitor置为1,并将对象的抢占该线程置为该线程。
2)如果该线程已经占用monitor,则直接进入,monitor数+1 (可重入锁)
3)如果该对象的抢占线程不是该线程,那么该线程就会被阻塞,直到monitor的数值变成0,再次抢占。

monitorexit指令:

执行monitorexit的线程必须是已经拥有该对象monitor的线程,执行monitorexit命令后,monitor的进入数会减1,当减为0时,其它线程就可以尝试获得monitor的所有权。

但是这里有一个疑问,为什么只有一个monitorenter,但是有两个monitorexit?

image.png

我们可以思考一下,这其实是和try/finally是一个道理,我们一般编程的时候,都要在finally里加一个解锁unlock,**防止异常情况的发生,那么这里也是一样的,为了防止代码出现异常,最后在进行monitorexit一下。
**

2.2synchronized普通同步方法

image.png

我们会发现,普通方法标志位多了一个ACC_SYNCHRONIZED访问标志

当我们调用一个方法的时候,会先检查方法的ACC_SYNCHRONIZED访问标志是否被设置,如果设置了,线程执行会先尝试获取monitor,最后在方法完成的时候释放monitor。

2.3synchronized静态同步方法

image.png

静态同步方法的原理也是一样的,不过再多一个ACC_STATIC标志位,用来区分是否静态同步方法。

3.总结

今天我们剖析了synchronized的字节码角度实现,其实多增加这种内功的修炼,会让我写代码的时候,有一种不一样的感觉,以前写synchronized的时候,脑子里只有单单一个synchronized关键字,现在又会联想到字节码,可能就是古人说的,从看山是山,到看山不是山的转变


苏凌峰
73 声望38 粉丝

你的迷惑在于想得太多而书读的太少。