轻量级锁 锁膨胀 自旋锁 偏向锁

1 Java对象头

普通对象

|---------------------------------------------------------------------|
|                         Object Header (64 bits)                     |
|----------------------------------|----------------------------------|
|        Mark Word (32 bits)       |       Klass Word (32 bits)       |
|----------------------------------|----------------------------------|

数组对象

|---------------------------------------------------------------------|----------------------------------|
|                                         Object Header (96 bits)                                        |
|----------------------------------|----------------------------------|----------------------------------|
|        Mark Word (32 bits)       |       Klass Word (32 bits)       |        array length (32 bits)    |
|----------------------------------|----------------------------------|----------------------------------|

其中 Mark word 结构为

|---------------------------------------------------------|--------------------|
|                     Mark Word (32 bits)                 |       State        |
|---------------------------------------------------------|--------------------|
|         hashcode: 25    | age: 4 | biased_lock: 0 | 01  |       Normal       |
|---------------------------------------------------------|--------------------|
|   thread: 23 | epoch: 2 | age: 4 | biased_lock: 1 | 01  |       Biased       |
|---------------------------------------------------------|--------------------|
|                  ptr_to_lock_record: 30           | 01  | Lightweight Locked |
|---------------------------------------------------------|--------------------|
|          	ptr_to_heavyweight_monitor: 30          | 00  | Heavyweight Locked |
|---------------------------------------------------------|--------------------|
|                                                   | 11  |    Mark for GC     |
|---------------------------------------------------------|--------------------|

2 Monitor

2.1 概念

是一个对象,当线程执行synchronized(obj)时,obj对象(锁对象)会将Mark Word被指向一个Monitor对象。

2.2 结构

在这里插入图片描述

2.3 流程

  • 刚开始 Monitor 中 Owner 为 null
  • 当Thread-2 执行 synchronized(obj) 就会将 Monitor 的所有者 Owner 置为 Thread-2,Monitor 中只能有一个 Owner。
  • 在Thread-2 上锁的过程中,Thread-3、Thread-4也来执行 synchronized(obj) ,就会进入EntryList 中阻塞BLOCKED。
  • 在Thread-2 执行完同步代码块的内容,然后唤醒 EntryList 中等待的线程来竞争锁,竞争是非公平的。
  • WaitSet中的 Thread-0、Thread-1是之前获得过锁,但条件不满足进入Waiting状态的线程。

3 轻量级锁

3.1 概念

当一个对象虽然有多线程访问,但多线程访问的时间错开的(也就是没有竞争),那么可以使用轻量级锁来优化。

3.2 举例

 static final Object lock = new Object();

 public static void method1() {
     synchronized (lock) {
         System.out.println("方法1...");
         method1();
     }
 }

 public static void method2() {
     synchronized (lock) {
         System.out.println("方法2...");
     }
 }

(1)线程-0 栈帧 里产生锁记录Lock record
Lock record 里锁对象的 Markword
Object refence 里存 锁对象地址
在这里插入图片描述
(2)让锁记录中的 Object refence指向锁对象,并尝试用cas替换 Object 的 MarkWord,将Mark Word的值存入锁记录。
在这里插入图片描述
(3)如果cas成功,对象头中存储了锁记录地址和状态 00 ,表示由该线程给对象加锁

在这里插入图片描述
(4)如果cas失败分为两种情况

  • 如果是其他线程已经持有了该Object的轻量级锁,这时表明有竞争,进入锁膨胀过程
  • 如果是当前线程synchronized锁重入,那么再添加一条 Lock Record作为锁重入的计数
    在这里插入图片描述
    (5)解锁1,如果有取值为null的锁记录;表示有锁重入,这时重置锁记录,表示重入计数减一
    在这里插入图片描述
    (6)解锁2,锁记录不为null;这时cas要将Mark word的值恢复给对象,
  • 成功 解锁成功
  • 失败 表示当前已经升级为重量级锁,进入重量级锁解锁流程

4 锁膨胀

4.1 概念

在尝试cas操作对对象加轻量级锁时发生竞争,那么轻量级锁会膨胀为重量级锁。

4.2 流程

(1)Thread-1 给 Object 加轻量级锁时发现 Thread-0已经对 Object 对象加了轻量级锁,那么进入锁膨胀
在这里插入图片描述
(2)为 Object 对象申请Monitor对象,让Object指向重量级锁地址
然后自己进入Monitor的EntryList BLOCKED 阻塞
在这里插入图片描述

5 自旋锁

重量级锁竞争的时候,还可以进行自旋进行优化,如果当前线程自旋成功(即这时候持锁线程已经退出了同步块,释放了锁)
这时当前线程就可以避免阻塞。
自旋成功的情况
在这里插入图片描述
自旋失败的情况
在这里插入图片描述

6 偏向锁

6.1 概念

轻量级锁没有竞争时,每次重入仍然需要执行CAS操作
JDK6中引入偏向锁来做进一步优化,只有第一次使用CAS将线程ID设置到MarkWord头,之后发现这个线程ID是自己的表示没有竞争,不需要重新CAS。以后不发生竞争,这个对象就归该线程所有

	static final Object lock = new Object();

    public static void method1() {
        synchronized (lock) {
            System.out.println("方法1...");
            method2();
        }
    }

    public static void method2() {
        synchronized (lock) {
            System.out.println("方法2...");
            method3();
        }
    }

    public static void method3() {
        synchronized (lock) {
            System.out.println("方法3...");
        }
    }

在这里插入图片描述
在这里插入图片描述

6.2 偏向状态

|---------------------------------------------------------|--------------------|
|                    Mark Word (64	 bits)                 |       State        |
|---------------------------------------------------------|--------------------|
| unused: 25 |hashcode: 25| age: 4 | biased_lock: 0 | 01  |       Normal       |
|---------------------------------------------------------|--------------------|
|   thread: 54 | epoch: 2 | age: 4 | biased_lock: 1 | 01  |       Biased       |
|---------------------------------------------------------|--------------------|
|                  ptr_to_lock_record: 62           | 01  | Lightweight Locked |
|---------------------------------------------------------|--------------------|
|          	ptr_to_heavyweight_monitor: 62          | 00  | Heavyweight Locked |
|---------------------------------------------------------|--------------------|
|                                                   | 11  |    Mark for GC     |
|---------------------------------------------------------|--------------------|
  • 默认情况开启的
  • 偏向锁是有延迟的,不会在程序启动时生效,如果想避免延迟,可以加VM参数 XX:BiasedLockingStartupDelay=0来禁用延迟
  • 如果没有开启偏向锁,那么对象创建后,markword 的值0x01即为最后三位001,这时hashcode、age都为0;hashcode懒加载

6.3 撤销

多个对象竞争时会将偏向锁撤销

6.4 批量重偏向

如果对象虽然被多个线程访问,但没有发生竞争,这时偏向了T1的对象仍然有机会重新偏向T2,重偏向会重置对象的ThreadID

  • 当撤销偏向锁的阈值超过20次后,jvm会认为是不是偏向错了,于是会在给对象加锁时重新偏向至加锁线程
  • 当撤销偏向锁的阈值超过40次后,jvm认为确实是偏向错了,根本就不该偏向,于是整个类的所有对象都会变成不可偏向的,新建的对象也变成不可偏向的

6.4 锁消除

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值