文章42
标签13
分类3

Java锁的实现原理

Java锁的实现原理

对象布局

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>
package com.greedring.lock;

import org.openjdk.jol.info.ClassLayout;

import java.util.concurrent.locks.ReentrantLock;

public class Test {

    static L l = new L();

    //给这个new出来的reentrantLock上锁
    static ReentrantLock reentrantLock = new ReentrantLock();

    public static void main(String[] args) {
        System.out.println(ClassLayout.parseInstance(l).toPrintable());
    }

    public static void lockTest() {

        //JUC并发包下提供的锁
        reentrantLock.lock();
        System.out.println("zzz");
        reentrantLock.unlock();

        //java的内置锁
        synchronized (l) {
            System.out.println("XXX");
            System.out.println("yyy");
        }
    }
}
package com.greedring.lock;

public class L {
    boolean flag = false;
}

l 中有一个标识改变来标记上锁成功,ReentrantLock中有一个state变量用来体现线程给他加了锁,那么 l 中这个变量在哪里体现标记上锁成功呢。

来看下Java中对象的组成:

  • OFFSET 偏移量,Java中内存上都是以指针形式存储,偏了多少位
  • SIZE 长度
  • TYPE DESCRIPTION 类型说明
    • object header 对象头(固定存在)
    • 实例数据
    • lose due to the next object alignment 对齐填充(64位JVM中对象必须以8byte去对齐)

对象头

对象的第一个部分,所有对象公共部分,由 Mark Word 和 Klass Pointer(Class Metadata Address)两个部分组成。

对象头是实现synchronized的锁对象的基础,一般而言,synchronized使用的锁对象是存储在Java对象头里的。

JVM中采用两个字来存储对象头:Mark Word + Klass Pointer 一共 12byte

openjdk(点我进入)中可以找到:

头对象结构 说明
Mark Word 存储对象的hashCode、锁信息或分代年龄或GC标志等信息
Klass Pointer 类型指针指向对象的类元数据,JVM通过这个指针确定该对象是哪个类的实例

虚拟机

cmd中输入java -version,可以看出使用的是HotSpot虚拟机

那么HotSpot和我们常提到的JVM是何关系:
JVM是虚拟机的规范或标准,HotSpot是产品或实现,其他的比如J9,taobaovm等都遵循了JVM规范。
由于HotSpot是由sun公司开发的,一般我们安装的都是这个。

openjdk(点我进入)中可以找到:

着重来看下这句话:
  Includes fundamental information about the heap object’s layout, type, GC state, synchronization state, and identity hash code.

  • 类型:以指针的形式保存在对象头中
  • GC状态:分为两种,Partial GC(并不收集整个GC堆的模式)和 Full GC(收集整个堆所有部分的模式)

对象分配的时候分配在eden区,当eden区空间不足时,就会发生Partial GC,将部分Eden中活跃对象放入Survivor区。Survivor区被用来作为Eden及Old的中间交换区域,当Old区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区。如果Old区空间不足,则会发生Full GC。

Survivor区到老年代,需要在from区和to区中发生15次的复制算法,from区和to区来回倒,倒一次年龄值就会加一次,年龄值记录在对象头中的某四位上,4bit最大能表示10进制的24,所以是0到15次。

  • 同步状态,当通过synchronized对对象进行加锁后,对象头中的某2bit就会发生改变。
  • 哈希代码:每个对象都有一个hash code,存储在对象头12个byte中的某个地方。
本文作者:GreedRing
本文链接:http://greedring.com/2019/12/13/lock/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可