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

相关推荐
Cc.Y4 小时前
Java零基础入门:类与对象深度掌握 —— 从“零散变量“到“打包管理“
java·开发语言·python
\光辉岁月/4 小时前
2.java变量
java·开发语言·变量
Wang's Blog4 小时前
Java 项目实战: 外卖平台优化-前端dist部署与Nginx反向代理rewrite
java·前端·nginx
专业程序开发源4 小时前
springboot生命故事书制作小程序65290-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·mysql·小程序·课程设计
代码山河4 小时前
Java的前世今生:从Oak语言到Java 23的发展史
java·学习·架构·教程·面向对象·项目
vx_Biye_Design4 小时前
springboot角色扮演服务平台65161-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·spring·课程设计
李游Leo4 小时前
HarmonyOS 7 QuickDock 闪控窗开发实录 02:floatView × floatingBall:形态切换、位置恢复与单一状态源【鸿蒙心迹】
java·华为·harmonyos
企业数字化笔记4 小时前
视频局部合成怎么做得自然?掩膜修复、边缘羽化、时序稳定与背景替换
java·javascript·音视频
仍然.4 小时前
Redis---主从复制
java·数据库·redis
vx_Biye_Design5 小时前
springboot咖啡厅顾客点单管理系统12080-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·spring·课程设计·express