自旋锁的简单实现

DaleLee / 2023-07-24 / 原文

实现

自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

自旋锁是互斥锁的一种实现,Java 实现如下方所示。

public class SpinLock {
    private AtomicReference<Thread> owner = new AtomicReference<Thread>();

    public void lock() {
        Thread currentThread = Thread.currentThread();
        // 如果锁未被占用,则设置当前线程为锁的拥有者
        while (!owner.compareAndSet(null, currentThread)) {
        }
    }

    public void unlock() {
        Thread currentThread = Thread.currentThread();
        // 只有锁的拥有者才能释放锁
        owner.compareAndSet(currentThread, null);
    }
}

测试

测试代码如下:

public class SpinLockTest {

    public static class Accumulator implements Runnable {
        SpinLock lock = new SpinLock();
        int i;

        @Override
        public void run() {
            for (int j = 0; j < 10000; j++) {
                lock.lock(); // 加锁
                i++;
                lock.unlock(); // 解锁
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Accumulator accumulator = new Accumulator();
        Thread t1 = new Thread(accumulator);
        Thread t2 = new Thread(accumulator);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(accumulator.i); // 预期值 20000
    }
}

输出如下:

20000

Process finished with exit code 0

优缺点

优点:

  • 自旋锁实现简单,同时避免了操作系统进程调度和线程上下文切换的开销。

缺点:

  • 第一个是锁饥饿问题。在锁竞争激烈的情况下,可能存在一个线程一直被其他线程“插队”而一直获取不到锁的情况。
  • 第二是性能问题。在实际的多处理上运行的自旋锁在锁竞争激烈时性能较差。

参考
Java AQS 核心数据结构-CLH 锁