AQS(AbstractQueuedSynchronizer)框架在Java并发编程中用于构建锁和其他同步器,它支持两种资源共享方式:独占(Exclusive)和共享(Shared)。
独占方式(Exclusive)
在独占方式下,一次只有一个线程能够访问资源。这种方式通常用于实现互斥锁,如ReentrantLock
。在AQS中,独占锁通过维护一个同步状态(一个volatile int
变量)来表示锁是否被某个线程持有。当线程成功获取锁时,它会将同步状态设置为表示锁已持有的值(通常是1或某个非零值),并继续执行其临界区代码。其他尝试获取锁的线程会发现同步状态表明锁已被持有,因此它们会被放入等待队列中等待,直到持有锁的线程释放锁并更新同步状态。
共享方式(Shared)
在共享方式下,多个线程可以同时访问资源。这种方式通常用于实现信号量(Semaphore)、读写锁(ReadWriteLock)中的读锁等。在AQS中,共享锁通过维护一个同步状态来表示可用资源的数量。当线程尝试获取共享资源时,它会检查同步状态的值,并尝试减少可用资源的数量(通常是通过原子操作)。如果同步状态的值表明有足够的资源可供使用(即减少后的值仍然非负),则线程获取资源并继续执行。如果同步状态的值表明没有足够的资源可供使用,则线程会被放入等待队列中等待,直到其他线程释放资源并更新同步状态。
实现细节
- 状态管理:AQS使用一个
volatile int
变量来存储同步状态,确保线程间的可见性。 - 等待队列:AQS内部维护了一个等待队列(也称为同步队列),用于存放等待获取同步资源的线程。等待队列是一个双向链表结构,每个节点代表一个等待获取锁的线程。
- 获取和释放:AQS提供了
acquire()
和release()
等方法来获取和释放锁(或资源)。这些方法在内部会根据独占或共享模式调用相应的tryAcquire()
、tryRelease()
、tryAcquireShared()
和tryReleaseShared()
等方法,这些方法需要在子类中实现具体的同步逻辑。
应用场景
- 独占锁:如
ReentrantLock
,用于确保一次只有一个线程能够执行某段代码。 - 共享锁:如
Semaphore
和读写锁中的读锁,用于允许多个线程同时访问共享资源,但限制同时访问的线程数量。
通过理解AQS的资源共享方式,开发者可以更好地利用Java并发库来编写高效、正确的并发程序。