MST

星途 面试题库

面试题:Java多线程编程中锁优化策略深度剖析

在Java多线程编程中,锁机制是保障线程安全的重要手段。请详细阐述从JDK1.6开始引入的各种锁优化策略,比如偏向锁、轻量级锁、自旋锁等,分析它们的适用场景、实现原理以及在不同应用场景下如何选择合适的锁优化策略以提升系统性能。
27.9万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. 偏向锁

  • 适用场景:适用于锁基本总是由同一线程持有,很少发生竞争的场景。比如单线程长时间访问同步块的情况。
  • 实现原理:当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID。以后该线程进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需要简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。如果测试成功,表示线程已经获得了锁。如果测试失败,则需要再测试一下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁):如果没有设置,则使用CAS竞争锁;如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。
  • 应用场景选择:在单线程频繁访问同步资源且很少有其他线程竞争的应用场景下,开启偏向锁能极大提升性能,因为减少了大量的锁获取和释放开销。

2. 轻量级锁

  • 适用场景:适用于线程交替执行同步块的场景,竞争不激烈,且持有锁的时间较短。
  • 实现原理:当线程要获取轻量级锁时,在当前线程的栈帧中创建一个锁记录(Lock Record),用于存储对象目前的Mark Word的拷贝(Displaced Mark Word)。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁;如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
  • 应用场景选择:在多线程竞争不激烈且持有锁时间较短的场景下,轻量级锁能避免重量级锁的系统调用开销,提高性能。例如在高并发但每个线程执行同步代码块时间很短的Web应用场景中,轻量级锁可以有效提升系统性能。

3. 自旋锁

  • 适用场景:适用于线程持有锁的时间较短,且CPU资源充足的场景。
  • 实现原理:当一个线程尝试获取一个被其他线程持有的锁时,该线程不会立即被挂起,而是在一定次数内循环尝试获取锁。如果在自旋次数内获取到锁,则继续执行;如果自旋超过一定次数仍未获取到锁,则该线程被挂起。
  • 应用场景选择:在多核CPU环境下,对于竞争不激烈且临界区执行时间短的同步操作,自旋锁可以避免线程上下文切换的开销,从而提升性能。例如在一些实时性要求较高的系统中,短时间内的锁竞争场景,自旋锁能提升系统响应速度。

4. 锁优化策略选择

  • 竞争程度低且持有锁时间短:优先选择偏向锁和轻量级锁。如果是单线程长期持有锁,偏向锁效果更好;如果是多线程交替持有锁,轻量级锁更合适。
  • 竞争程度高且持有锁时间长:此时偏向锁和轻量级锁的自旋优化可能失效,应考虑使用重量级锁,虽然重量级锁开销大,但能保证竞争激烈场景下的系统稳定性。
  • CPU资源充足且临界区执行时间短:自旋锁是不错的选择,通过自旋避免线程上下文切换开销,提升性能。但如果CPU资源紧张,过多的自旋会浪费CPU资源,此时不应使用自旋锁。