乐趣区

关于java:synchronized底层原理

synchronized 实现原理

synchronized 是 java 提供用于解决线程原子性操作相干问题的内置锁。对于每个对象来说,都有一个 monitor,你能够把它看做是一个同步工具,synchronized 须要通过操作 monitor 来实现锁的获取和开释。

当 synchronized 作用于 对象 的时候,反编译能够看到 2 个指令,monitorenter 和 monitorexit

当而 synchronized 作用于 办法 的时候,则是在标识符 flags 里增加一个 ACC\_SYNCHRONIZED 标记,来实现同步性能

当线程执行到 monitorenter 指令时,会去尝试获取 monitor,如果锁计数器为 0,就会将计数器 +1,其余线程就无奈获取以后对象的 monitor,没有获取到 monitor 的线程将会阻塞。如果再次重入 monitor,计数器会持续 +1。相同的,执行 monitorexit 指令时,会将计数器 -1,直到计数器为 0 的时候,以后线程会开释 monitor。

那么,monitor 又是如何工作的呢
进一步细化,对于 monitor 来说,有 2 个队列 entryList 和 waitSet,线程在申请获取 monitor 之前都会进入 entryList
1. 当有一个线程获取到 monitor 之后会进入一个 Owner 区域,同时对计数器进行 +1,此时对于 entryList 里的线程来说都是阻塞的,期待锁开释。
2. 进入 Owner 的线程调用 wait 办法,会开释 monitor,同时计数器 -1,并进入 waitSet 队列期待被唤醒,entryList 内的线程开始新一轮的竞争
3. 有线程调用 notify 办法的时候,waitSet 内的某个线程会被唤醒(当然,如果调用 notifyAll 会唤醒所有 wait 线程),线程会从新进入 entryList,去持续下一轮竞争
4. 执行完同步代码的线程会退出区域,同时开释锁

monitor 与对象关联

一个对象次要由三局部组成

对象头:包含 Mark Word 和 Class Pointer
实例数据:存储对象理论无效信息,类属性数据信息等
对齐填充:虚拟机要求对象的起始地址必须是 8 字节的整数倍,对齐填充相当于占位符的作用

对象头中的 Class Pointer 是指向对象类元数据的指针,由此获取对象是哪个类的实例
对象头的 Mark Word 次要存储对象的运行时数据,包含 hashcode,分代年龄,GC 标记,是否偏差锁,偏差锁线程 ID,轻量级锁指针,重量级锁指针等信息,对于 synchronize 来说,属于重量级锁,所以重量级锁指针就指向 monitor 的地址。

Mark Word 引出了一些锁的概念,比方偏差锁,轻量级锁,重量级锁,之后更新一期对于锁的分配机制和优化机制的文章,看一看 jvm 是如何优化内置锁的

退出移动版