面试题答案
一键面试锁粗化
- 工作原理:
- 将多次连续的加锁、解锁操作合并为一次,扩大锁的作用范围。比如在一个循环中多次对同一对象加锁解锁,JVM 会将这些操作优化为在循环外部加锁一次,循环结束后解锁一次。
- 生效场景:
- 当一系列连续操作都对同一个锁对象进行加锁解锁,且中间没有其他线程竞争该锁时,锁粗化能减少频繁加锁解锁带来的性能开销。
- 可能面临的问题:
- 锁粗化后,锁的持有时间变长,如果有其他线程竞争锁,会导致其他线程等待时间增加,降低系统的并发性能。
锁消除
- 工作原理:
- JVM 编译器在编译时,通过逃逸分析判断一个对象是否不会被其他线程访问,如果不会,则消除对该对象的加锁操作。例如一个局部对象,其只在方法内部使用,没有被其他线程访问的可能,那么对该对象的加锁操作会被消除。
- 生效场景:
- 适用于对象的使用范围局限在单个线程内,没有逃逸出该线程的场景。这种情况下,锁操作实际上是不必要的,锁消除可以避免无谓的锁开销。
- 可能面临的问题:
- 如果逃逸分析不准确,误将可能被其他线程访问的对象的锁消除,会导致线程安全问题。
偏向锁
- 工作原理:
- 偏向锁是为了在无竞争情况下减少锁获取的开销。当一个线程访问加锁对象时,会在对象头中记录该线程的 ID,以后该线程再次访问该对象时,发现对象头中的线程 ID 是自己的,则无需进行额外的加锁操作,直接进入同步块。只有当其他线程尝试访问该对象时,偏向锁才会被撤销,升级为轻量级锁。
- 生效场景:
- 适用于锁基本总是由同一个线程多次获取的场景,如单线程频繁访问某个加锁资源。这种情况下,偏向锁能极大提高性能,因为避免了每次加锁的开销。
- 可能面临的问题:
- 如果实际应用场景中锁竞争频繁,偏向锁不断被撤销和升级,会带来额外的性能开销。而且偏向锁的撤销需要等待全局安全点,可能会导致短暂的停顿。
轻量级锁
- 工作原理:
- 当偏向锁升级为轻量级锁时,线程在自己的栈帧中创建锁记录,将对象头中的 Mark Word 复制到锁记录中,然后尝试使用 CAS 操作将对象头中的 Mark Word 替换为指向锁记录的指针。如果 CAS 操作成功,线程获得锁;如果失败,表示有其他线程竞争锁,轻量级锁会膨胀为重量级锁。
- 生效场景:
- 适用于竞争不是特别激烈的场景。在这种场景下,轻量级锁通过 CAS 操作尝试获取锁,避免了重量级锁的线程阻塞和唤醒带来的开销,能提升性能。
- 可能面临的问题:
- 如果竞争过于激烈,CAS 操作失败频繁,轻量级锁会频繁膨胀为重量级锁,导致性能下降。而且 CAS 操作本身也有一定的开销,如果操作过于频繁,也会影响性能。