谈谈Java中synchronize的用法及其原理

Java面试 潘老师 8个月前 (09-04) 166 ℃ (0) 扫码查看

Java面试题:谈谈Java中synchronize的用法及其原理?

得分点:

作用于三个位置、对象头、锁升级

标准回答:

synchronized在Java中可以作用在三个不同的位置,分别对应三种不同的使用方式,这三种方式的区别在于锁对象的不同选择:

  1. synchronized作用在静态方法上时,锁对象是当前类的Class对象。
  2. synchronized作用在普通方法上时,锁对象是当前实例(即this)。
  3. synchronized作用在代码块上时,需要在关键字后的小括号中显式指定一个对象作为锁对象。

根据要锁定的范围,应准确选择锁对象以确定锁的粒度,以降低锁带来的性能开销。

synchronized的底层实现是依赖Java对象头来存储锁信息的,Java对象头包含三部分:Mark Word(标记字)、Class Metadata Address(类元数据地址)、Array length(数组长度,仅用于数组对象)。其中,Mark Word用于存储对象的hashCode以及锁信息。synchronized的锁信息包括锁的标志和锁的状态,这些信息存放在对象头的Mark Word部分。

锁的升级机制是Java中的一个重要优化策略,它旨在根据线程竞争情况逐步升级锁的状态以提高效率。从Java 6开始,锁被分为四种状态,从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。锁可以升级但不能降级,这是为了减小锁竞争带来的性能开销。

加分回答:

锁升级的过程可以根据实际场景来说明:

  1. 初始阶段,没有线程访问同步块,同步块处于无锁状态。
  2. 线程1访问同步块,尝试加偏向锁,由于没有竞争,偏向锁加锁成功,此时Mark Word存储线程1的ID。
  3. 线程2访问同步块,尝试加偏向锁,但因为存在竞争,偏向锁加锁失败,触发偏向锁的撤销过程,将锁恢复到可竞争状态。
  4. 线程1和线程2共同竞争,尝试加轻量级锁,假设线程1成功获取锁,但线程2不放弃,继续自旋等待。
  5. 如果线程1很快执行完,线程2也会加轻量级锁成功,锁不会升级为重量级锁。如果线程1执行时间较长,线程2放弃自旋后,会发起锁膨胀的过程,将锁升级为重量级锁,线程2进入阻塞状态。

总之,锁升级的机制使锁根据竞争情况逐步升级,只有在竞争激烈时才升级为重量级锁,以减小锁带来的性能开销。这是多线程编程中的重要性能优化策略。


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/javainterview/8634.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】