Java Semaphore 深度解析

一、Semaphore 概述

1.1 基本概念

Semaphore(信号量)是 Java 并发包 (java.util.concurrent) 中一个重要的同步工具类,用于控制同时访问特定资源的线程数量。它通过维护一组"许可"(permits)来实现资源访问的限制,线程必须获取许可才能访问资源,使用完毕后释放许可供其他线程使用。

1.2 核心特性

  • 资源访问控制:限制同时访问某资源的线程数量
  • 公平性选择:支持公平和非公平两种模式
  • 许可管理:可动态调整许可数量
  • 灵活获取:支持阻塞和非阻塞获取方式
  • 可中断操作:支持获取许可时的中断响应

二、Semaphore 实现原理

2.1 底层架构

Semaphore 基于 AQS (AbstractQueuedSynchronizer) 实现:

public class Semaphore implements java.io.Serializable {
   
   
    private final Sync sync;
    
    abstract static class Sync extends AbstractQueuedSynchronizer {
   
   
        // 构造方法
        Sync(int permits) {
   
   
            setState(permits);
        }
        
        // 非公平获取
        final int nonfairTryAcquireShared(int acquires) {
   
   
            for (;;) {
   
   
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
        
        // 释放许可
        protected final boolean tryReleaseShared(int releases) {
   
   
            for (;;) {
   
   
                int current = getState();
                int next = current + releases;
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))
                    return true;
            }
        }
    }
    
    // 非公平版本
    static final class NonfairSync extends Sync {
   
   
        // 实现略...
    }
    
    // 公平版本
    static final class FairSync extends Sync {
   
   
        // 实现略...
    }
}

2.2 工作流程

  1. 初始化:创建 Semaphore 并指定许可数量
  2. 获取许可:线程调用 acquire() 方法获取许可(减少许可数)
  3. 资源访问:获得许可后访问受限资源
  4. 释放许可:线程调用 release() 方法释放许可(增加许可数)
  5. 阻塞/唤醒:当无许可可用时,线程阻塞;许可释放时唤醒等待线程

三、Semaphore 核心方法详解

3.1 构造方法

// 创建具有给定许可数的非公平 Semaphore
public Semaphore(int permits) {
   
   
    sync = new NonfairSync(permits);
}

// 创建具有给定许可数和公平性设置的 Semaphore
public Semaphore(int permits, boolean fair) {
   
   
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

3.2 获取许可方法

// 获取一个许可,阻塞直到可用或线程被中断
public void acquire() throws InterruptedException {
   
   
    sync.acquireSharedInterruptibly(1);
}

// 获取一个许可,阻塞直到可用(不响应中断)
public void acquireUninterruptibly() {
   
   
    sync.acquireShared(1);
}

// 尝试获取许可,立即返回获取结果
public boolean tryAcquire() {
   
   
    return sync.nonfairTryAcquireShared(1) >= 0;
}

// 尝试获取许可,带超时等待
public boolean tryAcquire(long timeout, TimeUnit unit)
    throws InterruptedException {
   
   
    return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}

// 获取多个许可
public void acquire(int permits) throws InterruptedException {
   
   
    if (permits < 0) throw new IllegalArgumentException();
    sync.acquireSharedInterruptibly(permits);
}

3.3 释放许可方法

// 释放一个许可
public void release() {
   
   
    sync.releaseShared(1);
}

// 释放多个许可
public void release(int permits) {
   
   
    if (permits < 0) throw new IllegalArgumentException();
    sync.releaseShared(permits);
}

3.4 其他重要方法

// 返回当前可用许可数
public int availablePermits() {
   
   
    return sync.getPermits();
}

// 获取并返回所有立即可用的许可
public int drainPermits() {
   
   
    return sync.drainPermits();
}

// 减少许可数(缩减)
protected void reducePermits(int reduction) {
   
   
    if (reduction < 0) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦幻南瓜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值