1.什么是自旋锁?
作为锁的一种,自旋锁和互斥一样,也是并发环境中保护共享资源的一种锁机制。任何时候,只有一个执行单元可以获得锁。
[En]
As a kind of lock, spin lock, like mutex, is also a lock mechanism to protect shared resources in concurrent environment. At any time, only one execution unit can acquire the lock.
互斥锁通常利用操作系统提供的线程阻塞/唤醒机制实现,在争用锁失败时令线程陷入阻塞态而让出cpu,并在获取到锁时再将其唤醒。而自旋锁则是通过加锁程序中的无限循环,由当前尝试加锁的线程反复轮训当前锁的状态直到最终获取到锁。
互斥锁与自旋锁的优缺点
互斥锁的优点是当加锁失败时,线程会及时的让出cpu,从而提高cpu的利用率,但缺点是如果短时间内如果涉及到大量线程的加锁/解锁,则频繁的唤醒/阻塞会因为大量的线程上下文切换而降低系统的性能。因此互斥锁适用于线程会在较长时间内持有锁的场景。
与互斥锁相对的,自旋锁由于一直处于持续不断的轮训中,因此可以非常迅速的感知到锁状态的变化,在两个线程间能够瞬间完成锁的释放与获取。但如果需要争用锁的线程长时间都无法获取到锁,则会造成CPU长时间空转,造成CPU资源极大的浪费。因此自旋锁只适用于线程在加锁成功后会在极短的时间内释放锁的场景(需要保护的临界区非常小)。
自旋锁和互斥锁相辅相成,在不同的需求场景中各自发挥作用。
[En]
Spin lock and mutex lock play a complementary role, playing their own role in different requirements scenarios.
2.自旋锁的多种实现
本篇博客的重点是自旋锁的工作原理,由于存在许多种拥有不同特性的自旋锁,所以这里只挑选出几种具有代表性的自旋锁: 原始版本自旋锁、票锁TicketLock、CLH锁和MCS锁,介绍这几种自选锁的实现原理和各有的优缺点。
本篇博客中的自旋锁是用java实现的。为了方便测试,先抽象并定义了一个通用的自旋锁接口SpinLock。