并发-synchronized详解

JDK1.6之前的synchronized关键字一来就直接给对象加了一把重量级锁,频繁地在用户态和内核态之间切换,导致性能非常低。为了弥补synchronized的不足,大佬doug lee写了一个AQS框架,用Java语言实现了ReentrantLock。然后在JDK1.6之后,oracle优化了synchronized的锁过程,增加了锁的膨胀逻辑。当没有线程来调用synchronized修饰的代码时,synchronized为无锁态,当有一个线程调用时,synchronized由无锁态升级为偏向锁,当有多个线程都调用这块代码时,就会从偏向锁升级到轻量锁状态,这是没有获取到锁的线程就会进行自旋以获取锁。如果自旋太久一直没有获取到锁,就会升级为重量级锁。这个锁的膨胀过程大大提升了synchronized的性能。

对象锁


sy在JDK1.6之前:new Object();的时候jvm天然地维护一个管程monitor,monitor依赖底层的操作系统Mutex【互斥量】,mutex是由操作系统维护的【调操作系统的线程库Pthread】------------------------------为什么效率低呢?涉及到用户态与内核态之间的切换所以效率很低

基于sy锁太重影响性能的前提

开发出ReentrantLock锁,是基于java写的java类归于AQS框架。ReentrantLock可重入、公平性

oracle优化了synchronized的锁过程:
所以JDK1.6及之后,要是锁被一个线程占了,后面的线程就会自旋等待【不需要让出CPU的使用权,一直占着CPU】,浪费一点CPU资源,比阻塞自己回头等另外线程唤醒的效率高的多
只有重量级锁会依赖管程monitor
在这里插入图片描述

sy加锁

sy加在静态方法,锁是加在Class类上
sy加在普通方法,锁加在this,加在当前对象上
new 一个实例对象,对象锁

在同步代码块上sy(object)加锁:monitorenter和monitorexist【有几个,避免发生异常,不释放锁】
在方法上加锁public static synchorized void decrStock(){} 在翻译字节码后会给方法的修饰符加上ACC_synchorized 一标志,这个标志会触发JVM 底层给代码块加monitorenter和monitorexist
对象怎么记录锁的状态的呢

在这里插入图片描述
对象的内存多大:8字节的整数倍
在这里插入图片描述

对象锁的状态就记录在Mark Word,Mark Word大小为4字节大小,32比特大小【32位虚拟机,64位的话也会进行指针压缩】
在这里插入图片描述
匿名偏向—>加入sy对象锁就会偏向锁,并且有指向哪个线程的记录---->多个线程抢3同一把锁的话就会转为轻量级锁---->当自旋等待的时间过长的话就会升级为重量级锁

当对象可偏向时:markword将变成未锁定状态 并只能升级为轻量级锁
当对象正处于偏向锁时,调用hashcode将使偏向锁强制升级成重量级锁

在加锁的情况下,且处于偏向锁,这时候调用方法要回去hashcode,锁就会升级为轻量级锁,因为偏向锁没有记录hasdcode的地方,升级到轻量级锁后,mark word除了锁状态的其余部分会保存一个指针,指向一个地方,该地址保存初始状态的mark word 信息。如下图![在这里插入图片描述
【稍微更改】注意:调用hashcode方法的时候,就进入无锁,再次进入会升级为轻量级锁
重量级锁hashcode存在管程里
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

\

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值