返回

循序渐进理解AQS(1):站在源头的锁的实现

见解分享

引言

在多线程并行编程中,锁是协调线程访问共享资源不可或缺的工具,而AbstractQueuedSynchronizer(简称AQS)是Java并发编程中构建锁和同步器的基石。本文旨在以循序渐进的方式,从源头的锁的实现角度,带领读者理解AQS的精髓。

锁的本质

锁的本质在于控制线程对共享资源的访问,确保一次只有一个线程能够访问该资源。在实现锁时,需要解决两个核心问题:

  • 互斥性: 保证任意时刻至多有一个线程持有锁。
  • 公平性: 保证等待锁的线程能够按顺序公平地获得锁。

一个简单的锁实现

最简单的锁实现可以利用Java内置的synchronized

public class SimpleLock {
    private boolean locked = false;

    public void lock() {
        while (locked) {
            try {
                wait();
            } catch (InterruptedException e) {
                // 忽略中断异常
            }
        }
        locked = true;
    }

    public void unlock() {
        locked = false;
        notifyAll();
    }
}

这个简单的锁实现了互斥性,但没有公平性。当多个线程同时尝试获取锁时,获取锁的顺序是不确定的。

AQS:一个灵活高效的锁框架

AQS提供了构建锁和同步器的通用框架,它定义了一个抽象基类AbstractQueuedSynchronizer,并提供了许多钩子方法和状态属性,允许开发者灵活地实现各种锁和同步器。

AQS的核心思想

AQS的核心思想是:将锁的状态抽象为一个整型变量state,并通过tryAcquirerelease两个方法来对状态进行操作。

  • tryAcquire: 尝试获取锁。如果成功,返回true;否则,返回false
  • release: 释放锁。

实现互斥性

互斥性通过将state变量设置为一个非零值来实现。当一个线程获取锁时,它将state设置为一个非零值。当另一个线程尝试获取锁时,它会发现state不为零,从而返回false,表示无法获取锁。

实现公平性

公平性通过引入一个队列来实现。当一个线程无法获取锁时,它会将自己加入队列。当锁被释放时,队列中的第一个线程将获得锁。

小结

本文从源头的锁的实现角度入手,介绍了锁的本质,讨论了一个简单的锁的实现,并阐述了AQS的框架思想和核心机制。在后续的文章中,我们将继续深入探讨AQS的具体实现,分析其高效性和灵活性的秘密。