AQS源码解析之公平锁与非公平锁
发布时间: 2024-02-16 09:22:56 阅读量: 11 订阅数: 11
# 1. 引言
#### 1.1 介绍AQS(AbstractQueuedSynchronizer)的作用和基本原理
AQS(AbstractQueuedSynchronizer)是Java并发框架中提供的一个基础工具类,用于实现同步器的构建。它是实现锁和其他同步器(如Semaphore、CountDownLatch等)的核心组件。AQS提供了一套抽象的队列同步器接口,以及一些默认的实现,这些实现在实现自定义同步器时非常有用。
AQS的基本原理是通过一个FIFO队列来管理线程的竞争和排队。该队列中的节点(Node)代表线程,节点内部维护了相关的状态信息,如等待状态、锁的拥有者等。当线程获取锁时,如果锁是可用的,则线程可以直接获取锁;如果锁被其他线程持有,则当前线程会被包装成节点,并被放入队列尾部,进入等待状态。当锁的持有者释放锁时,AQS会通过相应的算法将等待队列中的线程唤醒并从队列中移除,使得其能够重新进行竞争。
#### 1.2 解释公平锁和非公平锁的概念和区别
公平锁和非公平锁是指在多个线程竞争同一个锁时,锁的获取顺序的不同策略。
- **公平锁**:在多个线程同时竞争一个锁时,会按照线程的请求顺序进行排队,先到先得。即先到的线程先尝试获取锁,而后到的线程会加入到等待队列,等待前面的线程释放锁后再进行竞争。公平锁保证了线程获取锁的顺序按照其到达的顺序,维护了系统的公平性。
- **非公平锁**:在多个线程竞争同一个锁时,不考虑线程的到达顺序,允许后到的线程直接获取锁,即插队。非公平锁的主要目标是为了提高系统的吞吐量和性能,允许后到的线程有机会直接获取锁,减少了等待的时间。
公平锁和非公平锁的区别在于对锁的获取顺序的处理策略,在某些场景下,公平锁会导致更高的线程切换开销,而非公平锁则会导致某些线程长时间无法获取到锁。因此,在实际应用中需要根据具体情况选择合适的锁策略。在接下来的章节中,我们将分析AQS在公平锁和非公平锁实现上的原理和区别。
# 2. AQS源码解析
在本章中,我们将深入探讨AQS(AbstractQueuedSynchronizer)的源码实现细节。首先,我们将介绍AQS的源码结构概述,然后分别对公平锁和非公平锁的实现原理进行详细解析。通过本章的学习,你将更好地理解AQS的内部机制,并能够熟练分析其源码实现。
#### 2.1 AQS源码结构概述
AQS是Java并发包中提供的一种同步器框架,其核心思想是通过一个FIFO队列来管理线程的排队和唤醒,从而实现对共享资源的访问控制。AQS主要由以下几个部分组成:
- **同步队列(Sync Queue)**:用于存放被阻塞的线程,以及管理线程获取锁的排队顺序。
- **State变量**:记录共享资源的状态,通过CAS操作进行状态变更。
- **内部同步器(Sync)**:定义了获取锁、释放锁等操作的接口,具体子类(如ReentrantLock、CountDownLatch等)实现这些操作的具体逻辑。
AQS的内部实现比较复杂,但核心思想是基于状态的抽象,具体的同步操作由继承AQS的具体子类来实现。接下来,我们将分别对公平锁和非公平锁的实现原理进行解析。
#### 2.2 公平锁实现原理解析
##### 2.2.1 公平锁的队列机制
在AQS内部,对于公平锁,同步队列中的节点按照线程请求的先后顺序排队。每个线程都会创建一个节点(Node)并加入到队列尾部进行排队等待获取锁。
具体来说,当一个线程请求获取锁时,如果发现当前有其他线程持有锁或者队列不为空,那么该线程会以排队的方式加入等待队列。同时,AQS会确保队列中的节点按照先后顺序依次获取锁,即先进入队列的线程先获得锁的访问权限。
##### 2.2.2 公平锁的获取与释放流程
对于公平锁,线程获取锁的过程通常包括以下几个步骤:
- 线程通过acquire方法尝试获取锁,如果获取失败就会加入到等待队列中,并进入自旋状态。
- 当锁释放时,AQS会按照队列中的顺序唤醒等待线程,使得等待队列中的线程按照FIFO顺序逐个获取锁。
上述是公平锁的主要实现原理,接下来我们将对非公平锁的实现原理进行类似的解析。
# 3. 公平锁与非公平锁对比分析
在理解了AQS源码的基础上,我们来对比分析公平锁和非公平锁的特点和适用场景。
#### 3.1 基本性能特征比较
- 公平锁:
- 优点:
- 公平性较强:保证等待时间较长的线程能够优先获取锁。
- 避免饥饿:所有线程都有获取锁的机会。
- 缺点:
- 竞争激烈时性能下降:线程需要竞争锁,可能导致额外的线程调度和上下文切换。
- 可能存在线程饥饿问题:某些线程可能一直无法获取到锁。
- 非公平锁:
- 优点:
- 性能较高:线程可以直接尝试获取锁,减少了线程上下文切换的开销。
- 可能减少线程饥饿:如果锁一直可用,就没有线程饥饿问题。
- 缺点:
- 不保证公平性:可能会导致某些线程长期无法获取到锁。
#### 3.2 对系统公平性的影响
- 公平锁:确保了线程的公平性,避免了某些线程长时间无法获取锁的问题,但在高并发情况下性能可能下降。
- 非公平锁:优先为当前线程分配锁资源,性能较高
0
0