AQS源码解析之锁的获取与释放
发布时间: 2024-02-16 09:21:22 阅读量: 13 订阅数: 12 ![](https://csdnimg.cn/release/wenkucmsfe/public/img/col_vip.0fdee7e1.png)
![](https://csdnimg.cn/release/wenkucmsfe/public/img/col_vip.0fdee7e1.png)
# 1. 介绍
## 1.1 AQS简介
AQS(AbstractQueuedSynchronizer)是Java中用于构建锁和同步器的框架。它提供了一种实现阻塞锁和相关同步器的强大方式,是并发工具包中许多同步组件的基础,比如ReentrantLock、Semaphore和CountDownLatch等。AQS使用一种简单且高效的方式来管理同步状态,提供了一个可重用的同步框架,可以支持基于FIFO等待队列的阻塞同步和解锁。
## 1.2 锁的基本概念
在多线程编程中,锁是用来控制对共享资源的访问的机制。当多个线程需要访问共享资源时,通过获取锁来确保同一时刻只有一个线程可以访问该资源,从而避免数据竞争和不一致性。
锁的基本概念可以分为两种:
- 共享锁:多个线程可以同时获取该锁,用于支持并发读取操作。
- 排它锁:同一时刻只有一个线程可以获取该锁,用于支持独占的写入操作。
在接下来的章节中,我们将深入探讨AQS框架中锁的获取、释放,以及其底层实现和源码解析。
# 2. 锁的获取
在多线程编程中,锁的获取是非常重要的操作,它可以保证线程对共享资源的访问是安全的。在AQS中,锁的获取主要涉及到共享锁与排它锁、锁的获取过程以及LockSupport类的使用。
#### 2.1 共享锁与排它锁
在AQS中,锁可以分为共享锁和排它锁。共享锁是一种允许多个线程同时获取的锁,用于支持多个线程同时对资源进行读取操作;而排它锁则只允许一个线程获取,其他线程需要等待该线程释放锁后才能获取,用于保证对资源进行写入操作时的排他性。
#### 2.2 锁的获取过程
AQS中的锁获取过程主要涉及到线程的阻塞等待和唤醒操作。当一个线程尝试获取锁时,如果锁已被其他线程占用,那么该线程会被阻塞,直到锁释放后被唤醒;如果锁未被占用,那么该线程可以顺利获取到锁。
#### 2.3 AQS中的LockSupport类
LockSupport是AQS中用于线程阻塞和唤醒的工具类,它可以让线程在获取锁时进行阻塞,以及在锁释放时进行唤醒。通过调用park()方法进行阻塞,以及调用unpark()方法进行唤醒,LockSupport类为AQS的锁获取过程提供了基础支持。
以上是锁的获取章节的详细介绍,接下来我们将深入讨论AQS中锁的释放过程。
# 3. 锁的释放
在本章中,我们将讨论锁的释放过程以及AQS中的Condition接口和独占模式与共享模式的切换。
#### 3.1 锁的释放过程
在AQS中,锁的释放是与锁的获取相对应的过程。当持有锁的线程已经完成了它所需的操作,需要释放锁,以便其他线程能够获取到锁并执行自己的操作。在AQS中,包含了相应的释放锁的方法,如`release()`等。
在释放锁的过程中,AQS会根据当前同步状态来决定是否需要唤醒等待队列中的线程,以便这些线程有机会获取到锁并执行。释放锁的过程是一个关键的操作,需要确保释放的时机是合适的,以避免出现死锁或者其他并发问题。
#### 3.2 AQS中的Condition接口
在AQS中,除了基本的独占锁和共享锁机制外,还提供了Condition条件队列的支持。Condition接口提供了类似于`wait()`和`notify()`方法的功能,允许线程在特定的条件下等待和唤醒。
Condition接口的方法包括`await()`、`signal()`和`signalAll()`等,在特定的场景下非常有用,可以实现复杂的线程协作逻辑,避免了使用synchronized和wait/notify方式进行线程间的通信和协调。
#### 3.3 AQS中的独占模式与共享模式切换
AQS中同时支持独占模式和共享模式的锁机制。在实际应用中,有些场景下需要同时支持独占和共享两种模式的锁,AQS提供了相应的支持。
在AQS中,可以通过`tryAcquireShared()`和`tryReleaseShared()`等方法来实现共享模式下的锁获取和释放,同时AQS内部也提供了对应的统一的队列维护和线程调度机制。
通过AQS中的独占模式与共享模式的切换机制,我们能够更加灵活地应用AQS来实现复杂的线程同步和协作逻辑,同时提高了代码的可维护性和可扩展性。
以上是关于锁的释放、AQS中的Condition接口以及独占模式与共享模式切换的讨论,下一章节将进一步深入探讨AQS的底层实现。
# 4. AQS的底层实现
在本节中,我们将深入探讨AQS(AbstractQueuedSynchronizer)的底层实现原理,包括其数据结构、同步器状态的获取和更新以及等待队列和同步队列的机制。
#### 4.1 AQS的数据结构
AQS的核心数据结构是基于一个FIFO的双向队列,用于存储处于等待锁状态的线程。在AQS内部,通过Node类来表示一个等待在同步器上的线程,Node内部维护了线程状态、前驱节点和后继节点等信息。AQS还维护了一个同步器状态(state)变量,用于表示同步器的状态,比如锁的状态等。在实际的锁实现中,通常会将state变量作为标识锁的状态的依据。
```java
// Node类用于表示等待在同步器上的线程
static final class Node {
// 线程状态,用int表示
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
// ...
volatile int waitStatus;
volatile Node prev;
volatile Node next;
// ...
}
// AQS的主要数据结构
static final class Sync extends AbstractQueuedSynchronizer {
// 同步器状态
private volatile int state;
// 等待队列的头节点和尾节点
private transient Node head;
private transient Node tail;
// ...
}
```
#### 4.2 AQS的同步器状态获取和更新
AQS通过一些原子性的CAS操作来更新同步器状态,以及实现线程加入等待队列和唤醒等待线程的操作。核心方法如compareAndSetState()、enq()和setHeadAndPropagate()等都是基于CAS操作来实现同步器状态的更新和线程的管理。
```java
// AQS中的CAS操作更新同步器状态
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
// AQS中的线程加入等待队列的操作
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
// AQS中唤醒等待线程的操作
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
head = node;
if ((propagate & PROPAGATE) != 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
```
#### 4.3 AQS中的等待队列和同步队列
AQS内部的等待队列和同步队列是基于双向链表实现的,等待队列用于存储因等待锁而被阻塞的线程,而同步队列则用于存储已经获取了锁的线程。AQS通过对节点的状态(例如waitStatus)进行管理,
0
0
相关推荐
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![-](https://csdnimg.cn/download_wenku/file_type_column_c1.png)
![-](https://csdnimg.cn/download_wenku/file_type_column_c1.png)
![-](https://csdnimg.cn/download_wenku/file_type_column_c1.png)
![-](https://csdnimg.cn/download_wenku/file_type_column_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)