Semaphore CountDownLatch
时间: 2023-11-03 15:00:32 浏览: 125
Semaphore和CountDownLatch都是Java并发编程中常用的同步工具。
Semaphore是一种计数信号量,可以控制同时访问某个资源的线程数量。它通过维护一定数量的许可证来限制线程的并发访问。当线程需要访问资源时,首先要获取一个许可证,如果没有可用的许可证,则线程将被阻塞,直到有其他线程释放许可证。Semaphore可以用于控制同时访问的线程数量,也可以用于控制同时执行的任务数量。
CountDownLatch是一种同步工具,它可以让一个或多个线程在其他线程执行完成之前等待。它通过维护一个计数器来实现,计数器初始值为指定的值,每当一个线程完成自己的任务时,计数器的值减1。当计数器的值为0时,所有等待的线程被释放。CountDownLatch可以用于控制线程的执行顺序,等待其他线程完成指定任务后再继续执行。
相关问题
详细严谨的解释基于AQS实现的三种锁ReentrantLock,Semaphore和CountDownLatch
<think>好的,我现在需要详细解释基于AQS(AbstractQueuedSynchronizer)实现的三种锁:ReentrantLock、Semaphore和CountDownLatch。首先,我得回忆一下AQS的基本原理,因为这三个类都是构建在AQS之上的。
AQS是一个用于构建锁和同步器的框架,核心是维护一个volatile的int状态变量和一个FIFO线程等待队列。它通过CAS操作来原子地更新状态,并且提供了acquire和release方法,让子类去实现具体的获取和释放逻辑。不同的同步器可以通过继承AQS并重写这些方法来实现不同的同步机制。
接下来,我要分别分析这三个类如何利用AQS。首先,ReentrantLock是可重入的独占锁,它允许同一个线程多次获取锁,通过记录持有锁的线程和重入次数来实现。Semaphore是信号量,控制同时访问资源的线程数,属于共享模式。CountDownLatch是倒计时门栓,让一个或多个线程等待直到计数器减到零,也是共享模式。
我需要详细说明每个类在AQS中的具体实现。比如,ReentrantLock的Sync内部类分为公平和非公平两种策略,通过tryAcquire方法实现。Semaphore使用AQS的状态表示可用许可数,acquire和release操作对应减少和增加许可。CountDownLatch的状态表示剩余计数,await方法等待状态变为零,countDown方法减少状态。
还要注意每个类的独特性,比如ReentrantLock的可重入性,Semaphore的共享许可,CountDownLatch的一次性使用。同时,需要比较它们在AQS中的不同实现方式,比如独占模式和共享模式的区别。
可能存在理解错误的地方:比如,是否所有这三个类都直接继承AQS?实际上,它们内部都有一个Sync内部类继承自AQS。另外,CountDownLatch是否可重用?答案是不,它是一次性的,而Semaphore可以重复使用。ReentrantLock的公平和非公平策略如何影响性能?需要简要说明。
此外,用户可能需要了解这些锁的典型使用场景和注意事项,比如避免死锁、正确释放资源等。在解释时,需要结合代码示例或结构图来更清晰地说明内部机制,但用户可能只需要文字描述。
最后,要确保逻辑严谨,层次分明,先总述AQS,再分述每个类,最后比较异同。避免技术细节错误,比如AQS的状态变量在不同类中的具体含义可能不同,需要准确区分。</think>---
基于 **AQS(AbstractQueuedSynchronizer)** 实现的锁和同步器是 Java 并发编程的核心组件。以下对 **ReentrantLock**、**Semaphore** 和 **CountDownLatch** 的实现原理进行详细分析,涵盖其设计模式、AQS 状态管理及核心方法实现。
---
### **1. AQS 核心机制**
AQS 通过 **状态变量(state)** 和 **CLH 队列**(双向线程等待队列)实现同步控制:
- **state**:通过 `volatile int` 表示资源状态(如锁持有次数、信号量许可数、倒计时值)。
- **CLH 队列**:以 CAS 维护线程排队与唤醒机制,支持独占模式(如 ReentrantLock)和共享模式(如 Semaphore、CountDownLatch)。
---
### **2. ReentrantLock:可重入独占锁**
#### **核心特性**
- **独占模式**:同一时刻仅一个线程可持有锁。
- **可重入性**:持有锁的线程可重复获取锁,通过 `state` 记录重入次数。
- **公平性**:支持公平锁(按等待顺序分配)和非公平锁(允许插队)。
#### **AQS 实现细节**
1. **Sync 内部类**
ReentrantLock 的同步逻辑由内部类 `Sync`(继承自 AQS)实现,分为 `NonfairSync`(非公平)和 `FairSync`(公平)。
2. **tryAcquire(int)**
- **非公平锁**:直接尝试 CAS 修改 `state`(允许插队):
```java
final boolean nonfairTryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) { // 直接尝试获取
setExclusiveOwnerThread(current);
return true;
}
} else if (current == getExclusiveOwnerThread()) { // 重入逻辑
setState(c + acquires);
return true;
}
return false;
}
```
- **公平锁**:在 CAS 前检查队列中是否有前驱节点,避免插队。
3. **tryRelease(int)**
释放锁时减少 `state`,若 `state == 0` 则完全释放:
```java
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
```
---
### **3. Semaphore:信号量(共享模式)**
#### **核心特性**
- **共享模式**:允许多个线程同时访问资源。
- **许可控制**:通过 `state` 表示可用许可数,`acquire()` 申请许可,`release()` 释放许可。
#### **AQS 实现细节**
1. **Sync 内部类**
分为公平和非公平策略,类似 ReentrantLock,但使用共享模式方法(如 `tryAcquireShared`)。
2. **tryAcquireShared(int)**
减少许可数,成功返回剩余许可,失败返回负数:
```java
protected int tryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 || compareAndSetState(available, remaining))
return remaining;
}
}
```
3. **tryReleaseShared(int)**
增加许可数,通过 CAS 循环确保原子性:
```java
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (next < current) // 防止溢出
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))
return true;
}
}
```
---
### **4. CountDownLatch:倒计时门栓(共享模式)**
#### **核心特性**
- **一次性屏障**:`state` 初始化后递减至零,触发等待线程继续执行。
- **共享释放**:调用 `countDown()` 减少计数,`await()` 阻塞直到 `state == 0`。
#### **AQS 实现细节**
1. **Sync 内部类**
重写 `tryAcquireShared` 和 `tryReleaseShared`,状态表示剩余计数。
2. **tryAcquireShared(int)**
检查状态是否为零,是则放行(返回 1),否则阻塞(返回 -1):
```java
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
```
3. **tryReleaseShared(int)**
递减计数,直到达到零:
```java
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c - 1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
```
---
### **5. 三类同步器的对比**
| **特性** | ReentrantLock | Semaphore | CountDownLatch |
|------------------------|------------------------|------------------------|------------------------|
| **同步模式** | 独占 | 共享 | 共享 |
| **state 含义** | 重入次数 | 可用许可数 | 剩余计数 |
| **是否可重入** | 是 | 否 | 否 |
| **是否公平** | 支持公平/非公平 | 支持公平/非公平 | 无公平性控制 |
| **重置能力** | 无 | 通过增减许可重置 | 一次性使用,不可重置 |
---
### **6. 关键设计差异**
1. **独占 vs 共享**
- ReentrantLock 使用 `acquire()`/`release()`(独占)
- Semaphore 和 CountDownLatch 使用 `acquireShared()`/`releaseShared()`
2. **状态管理**
- ReentrantLock:`state` 记录锁的持有次数。
- Semaphore:`state` 表示剩余许可数。
- CountDownLatch:`state` 表示倒计时剩余值。
3. **唤醒策略**
- 独占模式下(ReentrantLock),唤醒仅针对头节点线程。
- 共享模式下(Semaphore/CountDownLatch),唤醒可能传播至后续共享节点。
---
### **7. 典型问题与注意事项**
- **死锁风险**:ReentrantLock 需确保 `lock()` 与 `unlock()` 成对调用。
- **资源泄漏**:Semaphore 的 `acquire()` 必须匹配 `release()`。
- **一次性限制**:CountDownLatch 不可重复使用,需配合 CyclicBarrier 实现循环屏障。
---
### **总结**
ReentrantLock、Semaphore 和 CountDownLatch 均通过 AQS 的模板方法模式实现,**通过重写 `tryAcquire`/`tryRelease` 或 `tryAcquireShared`/`tryReleaseShared` 定义同步规则**。理解其底层机制有助于优化高并发场景下的资源协调与线程控制。
countdownlatch和semaphore
CountDownLatch是Java中的一个同步工具类,它可以让一个线程等待其他线程完成操作后再执行。CountDownLatch的作用类似于倒计时,它可以设置一个计数器,当计数器为时,等待的线程就可以继续执行。
Semaphore也是Java中的一个同步工具类,它可以控制同时访问某个资源的线程数量。Semaphore可以设置一个许可证数量,当许可证数量为时,其他线程就需要等待。每当一个线程访问完资源后,就需要释放一个许可证,以便其他线程可以访问。
阅读全文
相关推荐












