面试题答案
一键面试- 性能差异概述
- synchronized:是Java的内置关键字,由JVM实现,早期版本性能相对较差,因为它是一种重量级锁,获取和释放锁会涉及到内核态与用户态的切换。但从Java 6开始,JVM对其进行了很多优化,如偏向锁、轻量级锁等机制,大大提升了性能。
- Lock接口:是Java 5之后引入的,提供了比
synchronized
更灵活的锁控制。它通过AQS(AbstractQueuedSynchronizer)框架实现,性能在某些场景下表现优异。
- 竞争激烈程度不同时的表现
- 竞争不激烈时:
- synchronized:由于偏向锁和轻量级锁机制的存在,在竞争不激烈,锁基本不会被其他线程获取的情况下,synchronized的性能很好。偏向锁会偏向于第一个获取锁的线程,当该线程再次获取锁时,无需进行额外的同步操作,直接进入同步块,效率很高。轻量级锁在竞争稍微激烈一些(但还未达到重量级锁的程度)时,通过自旋的方式尝试获取锁,避免了线程的挂起和恢复,性能也不错。
- Lock接口:此时Lock接口中的实现类(如ReentrantLock),虽然也能正常工作,但由于其实现相对复杂,在竞争不激烈时,额外的开销会使其性能略逊于优化后的
synchronized
。例如ReentrantLock每次获取锁都需要进行一些AQS框架相关的操作,而synchronized
在偏向锁或轻量级锁状态下操作更简单直接。
- 竞争激烈时:
- synchronized:当竞争激烈,锁被频繁争用时,偏向锁和轻量级锁会升级为重量级锁,此时会涉及大量的线程上下文切换,性能会大幅下降。因为线程获取不到锁时会被挂起,放入等待队列,当锁释放时,唤醒等待队列中的线程,这个过程开销较大。
- Lock接口:以ReentrantLock为例,在竞争激烈时,它可以通过非公平锁的方式来提高性能。非公平锁在锁可用时,不考虑等待队列中的线程顺序,直接尝试将锁分配给新请求的线程,减少了线程切换的开销。此外,Lock接口还支持更细粒度的控制,如可中断的锁获取操作、超时获取锁等,在高竞争场景下可以更好地满足复杂业务需求,性能表现可能优于
synchronized
。同时,ReentrantLock可以使用读 - 写锁(ReadWriteLock),在读多写少的场景下,允许多个线程同时进行读操作,大大提高并发性能,而synchronized
无法做到这一点。
- 竞争不激烈时: