大白话解释:Synchronized原理

  说起synchronized的原理吧,必须要从jvm的内存结构说起。每一个对象在被创建出来的时候都会在堆中为其分配内存空间,每一个对象含有三个部分组成:对象头、实例数据、对齐填充,其中对象头又分为三部分:自身运行时数据、类型指针、数组长度(如果是一个数组对象的话)。其中自身运行时数据又被称为Mark Word,这个Mark Word中含有很多信息,例如:对象的哈希码,对象的分代年龄,GC标识,轻量级锁指针,重量级锁指针,偏向线程ID等等。其中的重量级锁指针指向一个Monitor对象,它是依赖MonitorObject来实现的,每一个对象在创建的时候都会为期分配一个Monitor对象,而这个MonitorObject是由C++编写的。

  好了,有了这些底层知识,切入主题。在java的字节码文件中有两个指令:monitorenter和monitorexit,根据虚拟机规范的要求,在执行monitorenter指令的时候,首先要尝试获取对象锁,也就是这个Monitor对象,如果当前对象没有被锁定,或者当前线程已经获取的该对象的锁,那么就会将锁的计数器加一。反之,在执行monitorexit指令的时候就将锁的计数器减一,如果获取对象所失败就会将其放进Monotor对象的_WaitSet队列当中,直到锁被释放为止。

  但值得注意的是,我们会发现在java字节码当中会出现不止一个monitorexit指令,可能一个monitorenter指令对应两个monitorexit指令。这是因为java虚拟机为了保证在方法出现异常的情况下也能保证monitorenter和monitorexit指令正常配对执行,虚拟机会自动生成一个异常时的monitorexit指令,保证在方法出现异常的时候Monitor对象也能正常被释放。

  以上说的是synchronized同步代码块的原理,但是同步方法并不是采用monitorenter指令和monitorexit指令,而是采用的ACC_SYNCHRONIZED标识,当字节码读取器执行到此的时候就知道下面的方法是一个同步方法了。

猜你喜欢

转载自blog.csdn.net/qq_37685457/article/details/89740888