AQS的锁和条件变量
发布时间: 2024-02-27 08:25:16 阅读量: 28 订阅数: 20
# 1. AQS概述
## 1.1 什么是AQS(AbstractQueuedSynchronizer)
AQS是Java中用于构建锁和其他同步器的框架。它通过内置的FIFO队列实现了一个基于CLH(Craig, Landin, and Hagersten)锁的自定义同步器。AQS提供了一组用于构建锁和其他同步工具的原子状态管理、线程阻塞和唤醒机制,可用于构建各种同步器,如ReentrantLock、Semaphore、CountDownLatch等。
## 1.2 AQS的作用和特点
AQS的主要作用是在实现同步器时提供一个框架,通过实现它的子类来实现自定义的同步器。AQS的特点包括可重入、独占/共享、条件等待和线程阻塞唤醒等功能。
## 1.3 AQS在Java中的应用场景
AQS在Java中被广泛应用于构建各种同步工具和锁,例如ReentrantLock、ReentrantReadWriteLock、Semaphore等。它可以很好地满足不同场景下的同步需求,支持独占式和共享式同步,并提供了条件等待和线程阻塞唤醒的功能,为并发编程提供了便利和灵活性。
# 2. AQS的锁实现
AQS(AbstractQueuedSynchronizer)是Java中用于实现同步器的基础框架,在并发编程中起着至关重要的作用。AQS通过内置的FIFO队列和状态变量来实现对锁的管理和控制,既可以支持独占锁(Exclusive lock),也可以支持共享锁(Shared lock)。
### 2.1 独占锁的实现原理
独占锁是指在同一时刻只能有一个线程持有锁,在AQS中通过实现`tryAcquire`和`tryRelease`方法来实现对独占锁的控制。以下是一个简单的独占锁的实现示例:
```java
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
class ExclusiveLock extends AbstractQueuedSynchronizer {
// 尝试获取独占锁
@Override
protected boolean tryAcquire(int arg) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// 释放独占锁
@Override
protected boolean tryRelease(int arg) {
if (getState() == 0) {
throw new IllegalMonitorStateException();
}
setExclusiveOwnerThread(null);
setState(0);
return true;
}
}
```
在上面的例子中,通过`tryAcquire`和`tryRelease`方法,我们实现了独占锁的获取和释放操作。可以看到,在获取锁时,会使用CAS操作将状态从0修改为1,并记录当前持有锁的线程;在释放锁时,会将状态重新置为0。
#### 总结:
- 独占锁实现原理简单明了,通过CAS和状态变量来实现对锁的控制。
- 对于独占锁,只有当前持有锁的线程才能执行临界区代码,其他线程需要排队等待。
### 2.2 共享锁的实现原理
共享锁是指可以有多个线程同时持有锁,在AQS中通过实现`tryAcquireShared`和`tryReleaseShared`方法来实现对共享锁的控制。以下是一个简单的共享锁的实现示例:
```java
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
class SharedLock extends AbstractQueuedSynchronizer {
// 尝试获取共享锁
@Override
protected int tryAcquireShared(int arg) {
for (;;) {
int current = getState();
int newCount = current + arg;
if (compareAndSetState(current, newCount)) {
return newCount;
}
}
}
// 释放共享锁
@Override
protected boolean tryReleaseShared(int arg) {
for (;;) {
int current = getState();
int newCount = current - arg;
if (compareAndSetState(current, newCount)) {
return true;
}
}
}
}
```
在上面的例子中,通过`tryAcquireShared`和`tryReleaseShared`方法,我们实现了共享锁的获取和释放操作。其中,在获取锁时,会根据当前的状态值来判断是否可以获取共享锁;在释放锁时,会逐步减少状态值。
#### 总结:
- 共享锁允许多个线程同时持有锁,适用于读多写少的场景。
- 共享锁的实现需要考虑并发性,确保线程安全性。
### 2.3 AQS中如何保证线程安全性
AQS作为同步器的基础框架,可以通过内置的原子操作 CAS 来保证对锁和状态的操作是线程安全的。在AQS中,通过内部的队列和状态变量来实现对锁的控制,在具体的锁实现中要保证对共享资源的访问是原子的、有序的,避免出现数据竞争等问题,从而保证线程安全性。
在AQS中,锁的获取与释放是通过 `acquire` 和 `release` 系列方法来实现的,这些方法中会涉及对状态值的操作,通过 CAS 操作保证对状态值的修改是原子的,确保操作的一致性。另外,AQS内置的队列机制可以保证对于锁的请求和释放是按照先进先出的顺序进行的,避免线程的饥饿等问题
0
0