Semaphore

用来限制同一时间访问某个资源的线程数量

核心方法

  • acquire() 获取一个许可,若无可用则阻塞等待

  • acquire(int permits) 一次获取多个许可

  • tryAcquire() 尝试获取,不阻塞,会返回 true/false

  • tryAcquire(long timeout, TimeUnit unit) 显示等待获取许可

  • release() 释放一个许可

  • availablePermits() 返回当前可用许可

  • drainPermits() 一次性拿走所有许可

示例

复制代码
public class SemaphoreDemo {
​
    private static final Semaphore semaphore = new Semaphore(3); 
    
    public static void main(String[] args) {
        
        for (int i = 0; i < 10; i++) {
            final int finalI = i;
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println("acquire semaphore");
                    System.out.println(Thread.currentThread().getName() + " execute " + finalI);
                    Thread.sleep(2000);
                } catch (Exception e) {
​
                } finally {
                    semaphore.release();
                    System.out.println("task finish and release semaphore");
                }
            }).start();
        }
    }
}

我们可以看到,控制台上每次只有 3 个线程可以执行任务

也可以尝试获取许可

复制代码
if (semaphore.tryAcquire()) {
    try {
        System.out.println("成功获取许可,执行任务");
    } finally {
        semaphore.release();
    }
} else {
    System.out.println("当前无许可可用,放弃执行");
}

也可以选择设置等待时间,而不是立即返回失败

复制代码
if (semaphore.tryAcquire(2, TimeUnit.SECONDS)) {
    try {
        System.out.println("在2秒内拿到了许可");
    } finally {
        semaphore.release();
    }
} else {
    System.out.println("2秒超时仍未拿到许可");
}

Semaphore 支持公平锁和非公平锁

复制代码
Semaphore semaphore = new Semaphore(3, true);

默认 false 非公平,后来的线程可能插队,吞吐量更高;true 公平,按线程申请顺序排队,吞吐量低,但更公平

接下来对比下 Semaphore 和其他限流手段

限流方式 作用范围 精度 是否分布式 优点 缺点
Semaphore 单JVM本地 并发数级 简单高效、轻量 无法跨实例全局限流
Guava RateLimiter 单JVM本地 QPS级 支持速率限制、平滑突发 精度较粗
Sentinel / Redis 分布式 QPS级 可动态调整限流规则 依赖外部组件
Nginx / Gateway API网关层 请求速率 统一控制入口 配置复杂

因此,Semaphore 适合保护内部资源(线程池、数据库连接、文件IO等)

相关推荐
兑生1 小时前
【灵神题单·贪心】1481. 不同整数的最少数目 | 频率排序贪心 | Java
java·开发语言
daidaidaiyu1 小时前
一文学习 Spring 声明式事务源码全流程总结
java·spring
零雲2 小时前
java面试:了解抽象类与接口么?讲一讲它们的区别
java·开发语言·面试
左左右右左右摇晃5 小时前
Java并发——synchronized锁
java·开发语言
sxlishaobin6 小时前
Java I/O 模型详解:BIO、NIO、AIO
java·开发语言·nio
彭于晏Yan6 小时前
Spring AI(二):入门使用
java·spring boot·spring·ai
有一个好名字6 小时前
vibe codeing 开发流程
java
兑生6 小时前
【灵神题单·贪心】3745. 三元素表达式的最大值 | 排序贪心 | Java
java·开发语言
polaris06307 小时前
Windows操作系统部署Tomcat详细讲解
java·windows·tomcat
卓怡学长7 小时前
m280本科生导师指导平台
java·数据库·spring·tomcat·maven·intellij-idea