You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

线程为何需获取信号量的多个许可?求acquire(int permits)示例

为什么要调用Semaphore的acquire(int permits)?

当调用acquire()获取1个许可就能访问共享资源时,acquire(int permits)的存在是为了应对需要批量占用资源配额的场景,核心价值在于:

  • 匹配资源的实际消耗粒度:有些共享资源不是以“单次访问”为最小单位,比如一个线程需要同时使用3个数据库连接、或者占用内存池的5个块,这时候一次性申请对应数量的许可,能精准匹配资源的实际使用量,避免资源被零散占用导致的浪费。
  • 原子性的配额申请:批量申请是原子操作,不会出现“申请了部分许可后被阻塞”的情况,从根源上避免了因资源碎片化引发的死锁或调度混乱。
  • 精细化的容量控制:比如系统总资源配额是固定值(如总带宽10单位),不同任务的资源消耗不同(大任务占3单位,小任务占1单位),通过acquire(int permits)可以灵活控制任务并发数,保证总资源不超限。

使用示例:基于带宽配额的下载任务控制

假设服务器总带宽配额为10,大文件下载需要占用3个带宽单位,小文件占用1个。用Semaphore来实现带宽的精细化管控:

import java.util.concurrent.Semaphore;

public class BandwidthController {
    // 总带宽配额为10
    private static final Semaphore bandwidthSemaphore = new Semaphore(10);

    public static void main(String[] args) {
        // 启动3个大文件下载任务
        for (int i = 0; i < 3; i++) {
            new Thread(() -> downloadLargeFile()).start();
        }
        // 启动4个小文件下载任务
        for (int i = 0; i < 4; i++) {
            new Thread(() -> downloadSmallFile()).start();
        }
    }

    private static void downloadLargeFile() {
        try {
            // 申请3个带宽配额
            bandwidthSemaphore.acquire(3);
            System.out.println(Thread.currentThread().getName() + " 开始大文件下载,占用3个带宽配额");
            // 模拟下载耗时
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 释放3个带宽配额
            bandwidthSemaphore.release(3);
            System.out.println(Thread.currentThread().getName() + " 完成大文件下载,释放3个带宽配额");
        }
    }

    private static void downloadSmallFile() {
        try {
            // 申请1个带宽配额
            bandwidthSemaphore.acquire(1);
            System.out.println(Thread.currentThread().getName() + " 开始小文件下载,占用1个带宽配额");
            // 模拟下载耗时
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 释放1个带宽配额
            bandwidthSemaphore.release(1);
            System.out.println(Thread.currentThread().getName() + " 完成小文件下载,释放1个带宽配额");
        }
    }
}

运行这段代码可以看到:3个大任务(各占3配额)会先占用9个配额,剩下1个配额只能启动1个小任务;当某个大任务完成释放3配额后,剩余的小任务才能陆续启动,始终保证总带宽配额不超过10。

内容的提问来源于stack exchange,提问作者taher bouali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 15:27:09