醋醋百科网

Good Luck To You!

Java并发工具:Semaphore

在Java中,Semaphore(信号量)是位于java.util.concurrent包中的一个同步工具类。它用于控制同时访问某一资源的线程数量,或者是同时执行某一任务的线程数量。信号量通常用来限制可以访问某些资源(物理或逻辑的)的线程数量。

核心机制

许可机制

Semaphore 维护一组虚拟许可,初始化时指定许可数量。线程通过 acquire() 尝试获取许可(支持阻塞或非阻塞方式),资源使用后通过 release() 释放许可。若许可数为 0,后续线程将阻塞直至有可用许可。

公平与非公平策略

支持公平模式(按请求顺序分配许可)和非公平模式(允许插队,默认策略),通过构造函数参数 fair 指定。

典型应用场景

资源访问限流

如数据库连接池、文件句柄池等场景,限制同时访问资源的线程数量。例如,仅允许 10 个线程同时使用数据库连接。

生产者-消费者模型

协调生产者和消费者的执行节奏,防止资源过载。例如,控制餐厅同时用餐的顾客数量。

多线程协作

实现线程间依赖关系的协调,例如要求多个前置任务完成后才能执行后续操作。

基本使用

核心方法

acquire():阻塞获取许可(支持中断)

tryAcquire():非阻塞尝试获取许可

release():释放许可

availablePermits():返回当前可用许可数

代码示例

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(5); // 初始化5个许可
        ExecutorService executor = Executors.newCachedThreadPool();
        for (int i = 0; i < 20; i++) {
            executor.execute(() -> {
                try {
                    semaphore.acquire();    // 获取许可
                    // 访问资源
                    System.out.println(Thread.currentThread().threadId());
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    semaphore.release();    // 释放许可
                }
            });
        }
        executor.shutdown();
    }
}

此示例限制最多 5 个线程同时执行资源访问。

注意事项

许可泄露

确保 release() 在 finally 块中执行,防止线程异常终止导致许可未被释放。

死锁风险

避免多个 Semaphore 嵌套使用时因获取顺序不一致引发死锁。

动态调整

可通过 drainPermits() 清空剩余许可,或通过构造函数动态调整总许可数(需同步控制)。

与 ReentrantLock 对比

跨线程释放:Semaphore 允许不同线程获取和释放许可,而 ReentrantLock 通常要求同一线程释放锁。

用途差异:Semaphore 用于控制资源并发数,ReentrantLock 用于保护临界区代码的原子性。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言