Java并发编程|第四篇:synchronized锁升级

系列文章

1.前言

根据上一篇文章Java并发编程|第三篇:synchronized锁,其实发现,synchronized(lock)的作用范围和lock锁的对象有关

我们先来看看对象在内存中的内存布局

2.对象内存布局

  1. 对象头

第一部分:存储对象自身的运行时数据,如哈希码GC分代年龄锁状态标志线程持有的锁偏向线程ID偏向时间戳等。

另一部分:类型指针,即对象指向它的元数据指针,虚拟机通过这个指针来确定这个对象是哪个类的实例如果对象是一个数组,那在对象头中还必须有一块用于记录数组长度的数据。

  1. 实例数据

对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。

  1. 对齐填充

占位符作用,hotSpot VM的自动内存管理系统要求对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数,当实例数据部分没有对齐时。就需要通过对齐填充来补全。

发现对象的对象头中关键字锁状态标志线程持有的锁偏向线程ID和锁有关系
在这里插入图片描述

2.1Mark Word

对象头中详细的分布

32位虚拟机中,不同锁状态,对象头存储的锁信息
在这里插入图片描述

3.锁优化

jdk1.6之前, 是基于重量级锁来实现的

既要保证数据安全,也要保证性能?

jdk1.6之后引入了锁升级的概念

无锁–>偏向锁–>轻量级锁–>重量级锁

锁升级的过程由jdk底层实现,并不需要用户干预,随着锁的升级,程序的性能逐渐降低

3.1场景

synchronized(lock){
    //同步代码块
}

假设有线程1和线程2

  1. 只有Thread1访问同步代码块(大部分情况下)–>引入偏向锁

    如果程序大多数时候不存在锁竞争,一个同步块一直只有一个线程访问,这种情况下引入了偏向锁的概念,减少获取锁的成本。

  2. Thread1和Thread2交替访问同步代码块–>升级轻量级锁

    在线程锁竞争不多,而且每个线程持有锁时间很短的情况下,通过让线程自旋的方式竞争锁,从而避免线程阻塞,CPU从用户态转到内核态代价比较大。

  3. 多个线程同时访问同步代码块–>膨胀为重量级锁

    线程高并发,自旋超过限制,线程阻塞。

3.2无锁–>偏向锁

3.2.1线程1执行步骤:

  1. 线程1访问同步代码块

  2. 检查lock对象的对象头(mark word)中是否存储了线程1

  3. 如果没有,则通过CAS替换,设置mark word中的线程ID为T1

CAS替换 (原子性操作,乐观锁)

Compare and swap(value,expect,update)

通过现有值value和预期值expect比较

  • 如果相同替换成功,表示一直是同一个线程1在访问

  • 如果不同替换失败,表示有多个线程访问

4.执行同步代码块

3.2.2线程2执行步骤:

  1. 线程2访问同步代码块
  2. 检查lock对象的对象头,发现存储的是线程1,CAS替换失败
  3. 撤销线程1的偏向锁,重新恢复成无锁状态
    在这里插入图片描述

3.3无锁->轻量级锁->重量级锁

3.3.1线程1执行步骤:

  1. 线程1访问同步代码块

  2. 通过CAS替换成功,设置mark word替换为轻量级锁

  3. 执行同步块

  4. CAS替换失败(线程2争夺锁膨胀为重量级锁),线程1释放锁,并唤醒线程2

3.3.2线程2执行步骤:

  1. 线程2访问同步代码块

  2. 通过CAS替换失败,自旋(一段时间或者一定次数的自旋)

    自旋

    无限循环,直到cas返回true,即拿到锁,return跳出循环

    for(;;){
        if(cas){
        	return;
        }
    }
    
  3. 如果获取到锁,执行同步块

  4. 如果一直未获取到锁,在一段时间或者一定次数的自旋之后,锁膨胀升级为重量级锁

  5. 线程2阻塞

  6. 线程1执行完,释放锁,唤醒线程2

  7. 线程2重新争夺锁执行同步块
    在这里插入图片描述

4.参考

腾讯课堂->咕泡学院->mic老师->并发编程基础

5.系列链接

上一篇:Java并发编程|第三篇:synchronized锁
下一篇:Java并发编程|第五篇:可见性,java内存模型

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值