轻量级锁 Synchronized锁剖析
2023-10-02 14:58:45
轻量级锁 Synchronized锁
在 Java 中,Synchronized 是一种同步机制,用于控制对共享资源的访问。它通过使用互斥量(Mutex)来实现,互斥量是一种操作系统提供的机制,用于确保只有一个线程能够同时访问共享资源。
传统锁的性能问题
在传统的 Java 实现中,Synchronized 锁存在一些性能问题。这些问题主要是因为互斥量是操作系统提供的机制,需要进行内核态和用户态之间的切换,而这种切换是比较昂贵的。此外,互斥量还存在一些其他性能问题,例如:
- 互斥量可能会导致死锁。
- 互斥量可能会导致线程饥饿。
- 互斥量可能会导致线程优先级反转。
轻量级锁的演变
为了解决传统锁的性能问题,Java 5 引入了轻量级锁(Lightweight Lock)。轻量级锁是一种基于自旋(Spin)的锁,它通过不断地尝试获取锁来避免内核态和用户态之间的切换。如果在一段时间内无法获取锁,轻量级锁会升级为重量级锁(Heavyweight Lock)。
轻量级锁的引入极大地改善了 Synchronized 锁的性能。然而,轻量级锁也存在一些问题,例如:
- 轻量级锁可能会导致线程饥饿。
- 轻量级锁可能会导致线程优先级反转。
轻量级锁的底层实现
轻量级锁的底层实现是基于一个称为对象监视器(Object Monitor)的数据结构。对象监视器包含了一个锁标志(Lock Flag)和一个等待队列(Wait Queue)。锁标志用于指示锁的状态,等待队列用于存储正在等待获取锁的线程。
当一个线程想要获取锁时,它会先尝试获取对象监视器的锁标志。如果锁标志是空闲的,则线程可以成功获取锁。如果锁标志已经被其他线程占用,则线程会被放入等待队列中。
当一个线程释放锁时,它会将对象监视器的锁标志设置为释放状态,并唤醒等待队列中的第一个线程。唤醒的线程会尝试获取锁标志,如果成功则获取锁,否则会被重新放入等待队列中。
轻量级锁的优化方式
为了进一步提高轻量级锁的性能,Java 6 引入了偏向锁(Biased Lock)和自适应自旋(Adaptive Spin)等优化方式。
偏向锁是一种优化方式,它允许一个线程在没有竞争的情况下独占地访问共享资源。当一个线程第一次获取锁时,它会将锁标记为偏向锁。偏向锁只允许拥有偏向锁的线程访问共享资源,其他线程无法获取锁。
自适应自旋是一种优化方式,它允许轻量级锁在自旋一段时间后升级为重量级锁。自适应自旋的时间长度是根据锁的竞争情况动态调整的。如果锁的竞争情况比较激烈,则自旋的时间长度会比较短。如果锁的竞争情况不激烈,则自旋的时间长度会比较长。