Semaphore - 信号量
1. Semaphore - 信号量
1.1. 信号量模型
信号量的定义:
Semaphore(信号量):是并发编程中的一种线程同步工具,控制同时访问某资源的线程数量。
模型结构:
- 计数器(count)
- 等待队列(queue)
- 三个原子操作方法:
-
init(int c)
:初始化计数器值为 cdown()
(Java 中为acquire()
):
-
-
count--
,若结果 < 0,则阻塞线程,加入等待队列
-
-
up()
(Java 中为release()
):
-
-
count++
,若结果 ≤ 0,唤醒等待队列中的一个线程
-
特点:
- 原子性由 Java 的
Semaphore
实现保证 down()
/up()
也称为:P()
/V()
,或semWait()
/semSignal()
代码话信号量模型:
class Semaphore{// 计数器int count;// 等待队列Queue queue;// 初始化操作Semaphore(int c){this.count=c;}// void down(){this.count--;if(this.count<0){// 将当前线程插入等待队列// 阻塞当前线程}}void up(){this.count++;if(this.count<=0) {// 移除等待队列中的某个线程 T// 唤醒线程 T}}
}
示例:使用 Semaphore 实现互斥访问(类似锁)
static int value = 0;
static final Semaphore s = new Semaphore(1); // 1 表示只能一个线程访问static void addOne() {s.acquire(); // 进入前尝试获取许可证try {value += 1;} finally {s.release(); // 离开后释放许可证}
}
执行逻辑分析:
- 如果有两个线程同时
acquire()
:
-
- 一个成功(count = 0),继续执行
- 一个阻塞(count = -1)
- 当执行完后
release()
,阻塞的线程才被唤醒 - 实现了互斥访问
1.2. 实现限流器
Semaphore 的优势 —— 可支持多个线程访问
Lock
只能实现一个线程进入临界区Semaphore
可支持 多个线程同时访问资源
场景举例:对象池(或连接池)
class ObjPool<T, R> {final List<T> pool;final Semaphore sem;ObjPool(int size, T t) {pool = new Vector<>();for (int i = 0; i < size; i++) {pool.add(t);}sem = new Semaphore(size); // 控制最多 size 个线程访问}R exec(Function<T, R> func) {T t = null;sem.acquire(); // 尝试获取资源许可try {t = pool.remove(0); // 从池中取出对象return func.apply(t); // 执行业务逻辑} finally {pool.add(t); // 归还对象sem.release(); // 释放许可}}
}
核心逻辑:
- 控制同时最多有 N 个线程访问资源
- 获取资源 → 使用资源 → 归还资源
- 限流 + 对象复用(高效)