Java并发编程七之synchronized的实现原理

2020-05-25  本文已影响0人  echoSuny

monitorenter和monitorexit

在Java多线程的情况下经常会出现很多的问题,即使是简单的++操作也会每次执行的结果都不一样。于是我们经常使用下面这样的方式对我们所执行的代码块使用synchronized进行加锁来保证程序的正确执行。

public class Test {

    private volatile int count;
   
    public void incCount() {
        synchronized (this) {
            count = count + 1;
        }
    }
}

首先我们先把程序运行一下,之后再通过javap -v Test.class来反编译。反编译之后的结果如下图所示:


image.png

其中真正执行count = count + 1的指令是第4条到第14条指令。我们可以看到在执行count = count +1 的前后出现了两条指令monitorenter和monitorexit。这两条指令是由虚拟机在把我们的java文件编译成class文件的时候由编译器帮我们插入的。这其实就是synchronized真正的底层实现。当java虚拟机执行到monitorenter这一行指令的时候,表示现在要获取锁,也就是要获取一个Monitor对象的所有权。谁拿到了这个Monitor对象谁就获得了执行权。

锁的存放位置

在虚拟机中一个对象的内存布局分为对象头、实例数据、对齐填充。
对象头又有两部分信息:

synchronized进行的优化

锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态
下图是各种锁在变化的时候对对象头进行的修改:



我们知道synchronized是一个比较重的操作,被阻塞的线程会被挂起,发生上下文切换。而一次上下文切换的时间大概相当于5000~20000个CPU时间周期。于是java开发人员就对synchronized进行了一系列的优化。要理解synchronized所做的优化首先要了解一些锁的概念:

上一篇 下一篇

猜你喜欢

热点阅读