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等)

相关推荐
一灯架构8 小时前
90%的人答错!一文带你彻底搞懂ArrayList
java·后端
Y4090019 小时前
【多线程】线程安全(1)
java·开发语言·jvm
布局呆星10 小时前
SpringBoot 基础入门
java·spring boot·spring
风吹迎面入袖凉10 小时前
【Redis】Redisson的可重入锁原理
java·redis
w61001046610 小时前
cka-2026-ConfigMap
java·linux·cka·configmap
语戚11 小时前
力扣 968. 监控二叉树 —— 贪心 & 树形 DP 双解法递归 + 非递归全解(Java 实现)
java·算法·leetcode·贪心算法·动态规划·力扣·
quxuexi11 小时前
网络通信安全与可靠传输:从加密到认证,从状态码到可靠传输
java·安全·web
hrhcode12 小时前
【java工程师快速上手go】二.Go进阶特性
java·golang·go
小碗羊肉14 小时前
【从零开始学Java | 第三十一篇下】Stream流
java·开发语言