java的synchronized关键字

锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。

synchronize用的锁是存储在Java对象头里的。

长度内容说明
32/64bitMark Word存储对象的Hashcode、锁信息等
32/64bitClass Metadata Address存储到对象类型数据的指针
32/64bitArray Length数组的长度(如果当前对象是数组)

Mark Word的状态变化

锁状态是否是偏向锁锁标记位
无锁01
偏向锁101
轻量级锁00
重量级锁10

锁的状态变化

无锁升级为偏向锁:第一个线程来获取锁,升级为偏向锁。这个线程成为锁的偏向线程。

偏向锁升级为轻量级锁:偏向线程释放了锁,其他线程(非偏向线程)来获取锁,升级为轻量级锁。

偏向锁升级为重量级锁:偏向线程没有释放锁,其他线程来获取锁,存在竞争,升级为重量级锁。

轻量级锁升级为重量级锁:线程A是偏向线程,线程A释放了锁,线程B来获取锁,升级为轻量级锁,线程B未释放锁,线程C来获取锁,升级为重量级锁。

锁的一些特点

1.轻量级锁不存在锁的竞争,只要存在锁的竞争,一定是重量级锁。

2.不管偏向锁还是轻量级锁,只要存在锁的竞争,就升级为重量级锁。

3.锁升级之后不能逆向降级。

一、偏向锁

对象头的Mark Word里存储偏向线程ID。

当前线程的栈帧的锁记录里存储偏向线程的ID。

1.偏向锁的撤销

有线程来竞争偏向锁的时候才会释放锁。

对象头的Mark Word要么偏向于其他线程、要么恢复到无锁或者标记对象不适合作为偏向锁。

删除当前线程的栈帧里存储的锁记录。

二、轻量级锁

1.轻量级锁加锁

线程在执行同步块之前,JVM会先在当前线程的栈帧中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中。

然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。

2.轻量级锁解锁

对应轻量级锁的加锁,将栈帧中存储的锁记录替换回对象头。

三、重量级锁

重量级锁的实现使用内核中的互斥量mutex实现。

当锁是重量级锁状态,其他线程试图获取锁时,都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮的夺锁之争。

四、不同锁的优缺点

优点缺点适用场景
偏向锁加锁和解锁不需要额外的消耗,和执行非同步方法相比仅存在纳秒级的差距如果线程间存在锁竞争,会带来额外的锁撤销的消耗适用于只有一个线程访问同步块场景
轻量级锁竞争的线程不会阻塞,提高了程序的响应速度自旋消耗CPU资源追求响应速度
重量级锁线程竞争不使用自旋,不会消耗CPU线程阻塞,响应慢追求吞吐量

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值