MST
星途 面试题库

面试题:Java可重入锁的性能优化及锁升级策略

在高并发场景下,Java可重入锁的性能可能成为瓶颈。请阐述你对可重入锁性能优化的理解,比如锁粗化、锁消除等技术在可重入锁场景中的应用。另外,说明一下可重入锁是否存在类似Synchronized锁的锁升级策略,如果有,详细描述其过程和原理。
25.3万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

可重入锁性能优化理解

  1. 锁粗化
    • 原理:在某些情况下,如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作出现在循环体中,频繁的加锁解锁操作会导致性能损耗。锁粗化就是将多次连续的加锁、解锁操作合并成一次,扩展锁的作用范围。
    • 在可重入锁场景中的应用:例如,在一个循环体内对同一个可重入锁进行加锁解锁操作,如ReentrantLock lock = new ReentrantLock();,在循环for (int i = 0; i < 1000; i++) { lock.lock(); // 业务操作 lock.unlock(); } ,可以将锁粗化,把加锁操作移到循环体外,lock.lock(); try { for (int i = 0; i < 1000; i++) { // 业务操作 } } finally { lock.unlock(); },这样减少了加锁解锁的次数,提高性能。
  2. 锁消除
    • 原理:Java虚拟机(JVM)在运行时,通过对运行上下文的扫描,去除不可能存在竞争的锁。这是基于逃逸分析技术,JVM分析对象的作用域,如果对象只在一个线程内使用,没有逃逸出线程,那么对该对象的加锁操作是无意义的,可以消除。
    • 在可重入锁场景中的应用:比如在一个方法内创建了一个局部对象,并对该对象使用可重入锁进行同步操作,但该对象始终未逃出该方法作用域,JVM可能会消除对这个对象的可重入锁操作,因为不存在线程竞争。

可重入锁与Synchronized锁升级策略

  1. 可重入锁没有类似Synchronized锁的锁升级策略
    • Synchronized锁升级策略
      • 无锁状态:当一个对象刚开始没有任何线程访问时,处于无锁状态。
      • 偏向锁:当第一个线程访问该对象时,会在对象头中记录该线程的ID,以后该线程再次访问该对象时,只需要检查对象头中的线程ID是否与自己一致,无需进行CAS操作,提高了性能。如果有其他线程访问,偏向锁会被撤销。
      • 轻量级锁:偏向锁撤销后,会升级为轻量级锁。多个线程在不同时间段交替访问该对象时,线程会在自己的栈帧中创建锁记录,通过CAS操作将对象头中的Mark Word替换为指向锁记录的指针。如果CAS操作成功,线程获得锁,否则自旋尝试获取锁,自旋一定次数后还未获取到锁,会升级为重量级锁。
      • 重量级锁:当轻量级锁自旋失败后,升级为重量级锁。此时其他线程访问该对象,会被阻塞进入等待队列,等待持有锁的线程释放锁。
    • 可重入锁(如ReentrantLock):ReentrantLock基于AQS(AbstractQueuedSynchronizer)框架实现,主要通过FIFO队列来管理等待获取锁的线程,没有像Synchronized那样的锁升级过程。它通过一个int类型的变量来记录锁的持有次数(可重入特性),获取锁和释放锁的操作围绕这个变量和AQS队列进行,相对来说机制较为简单直接,不依赖于锁升级来优化性能。