Semaphore详解

186 阅读3分钟

Semaphore 是 Java 并发工具类,基于 许可证(Permits)机制 控制同时访问共享资源的线程数量。常用于限流、资源池管理、生产者-消费者模型等场景,支持公平与非公平模式。

一、核心功能

  1. 流量控制:限制同时访问资源的线程数量(如数据库连接池)。
  2. 许可证管理:线程通过 acquire() 获取许可证,release() 释放许可证。
  3. 模式可选:支持公平模式(按等待顺序分配)与非公平模式(允许插队)。

二、核心方法

方法说明
Semaphore(int permits)构造方法,指定许可证数量(默认非公平模式)
Semaphore(int permits, boolean fair)指定许可证数量和公平性
void acquire()获取一个许可证(阻塞直到获取或中断)
boolean tryAcquire()尝试获取许可证(非阻塞,立即返回结果)
boolean tryAcquire(long timeout, TimeUnit unit)带超时的尝试获取
void release()释放一个许可证(需与 acquire() 配对使用)
int availablePermits()返回当前可用许可证数量
void reducePermits(int reduction)减少许可证数量(Java 17+)

三、典型使用场景

  1. 资源池管理 例如:限制数据库连接池的最大并发连接数。
  2. 接口限流 例如:控制每秒处理请求的线程数量。
  3. 生产者-消费者模型 通过信号量协调生产者和消费者的速率。

四、代码示例(停车场模型)

public class SemaphoreDemo {
    public static void main(String[] args) {
        int parkingSpots = 3; // 3个车位
        Semaphore semaphore = new Semaphore(parkingSpots, true); // 公平模式
​
        for (int i = 1; i <= 5; i++) { // 5辆车竞争车位
            new Thread(() -> {
                try {
                    semaphore.acquire(); // 获取车位
                    System.out.println(Thread.currentThread().getName() + " 停车成功");
                    Thread.sleep(2000); // 模拟停车时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release(); // 释放车位
                    System.out.println(Thread.currentThread().getName() + " 离开车位");
                }
            }, "车辆-" + i).start();
        }
    }
}

输出结果

车辆-1 停车成功  
车辆-2 停车成功  
车辆-3 停车成功  
车辆-1 离开车位  
车辆-4 停车成功  
车辆-2 离开车位  
车辆-5 停车成功  
...(后续交替执行)  

五、注意事项

  1. 许可证必须释放 确保在 finally 块中调用 release(),避免线程阻塞导致资源泄漏。
  2. 避免超额释放 释放次数不应超过获取次数(否则许可证数量会异常增加)。
  3. 公平模式开销 公平模式基于队列维护顺序,性能略低于非公平模式。
  4. 动态调整许可证 Java 17+ 支持 increasePermits()reducePermits(),但需注意线程安全。

六、对比其他同步工具

特性SemaphoreReentrantLockCountDownLatch
核心能力控制并发数量互斥锁等待事件完成
可重用性支持支持(需解锁)一次性
公平性可选可选

七、高级用法

1. 多资源单位申请(批量获取许可证)

semaphore.acquire(2); // 一次获取2个许可证(需足够可用)
semaphore.release(2); // 释放2个许可证

2. 非阻塞尝试(快速失败)

if (semaphore.tryAcquire()) { // 立即返回是否成功
    try { /* 使用资源 */ } 
    finally { semaphore.release(); }
} else {
    System.out.println("资源不足,拒绝请求");
}

3. 动态扩容(Java 17+)

semaphore.reducePermits(2); // 减少2个许可证(如资源故障)
semaphore.increasePermits(2); // 增加2个许可证(如资源恢复)

总结Semaphore 是灵活的资源并发控制器,通过许可证机制实现精准的流量限制。适用于资源池化、接口限流等场景,需注意许可证的获取与释放必须严格匹配,避免死锁和资源泄漏。