源码分析--Semaphore

Semaphore是Java并发工具类,用于限制并发访问资源的线程数量。它提供了acquire()和release()方法进行许可的获取与释放。Semaphore内部使用AQS(AbstractQueuedSynchronizer)实现,有公平和非公平两种模式。公平模式下线程按等待顺序获取许可,而非公平模式则不保证公平性。源码中,FairSync和NonFairSync分别实现了公平和非公平的获取策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

Semaphore 是并发包中的一个工具类,可理解为信号量。通常可以作为限流器使用,即限制访问某个资源的线程个数,比如用于限制连接池的连接数。

主要方法如下:
在这里插入图片描述
其中主要方法是 acquire() 和 release() 相关的一系列方法,它们的作用类似。

void acquire():从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
void release():释放一个许可,将其返回给信号量。
int availablePermits():返回此信号量中当前可用的许可数。
boolean hasQueuedThreads():查询是否有线程正在等待获取。

源码分析

构造器

// 初始化 Semaphore,传入指定的许可数量,非公平
public Semaphore(int permits) {
    sync = new NonfairSync(permits);
}

// 初始化 Semaphore,传入指定的许可数量,指定是否公平
public Semaphore(int permits, boolean fair) {
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

构造器初始化了 Sync 变量,根据传入的 fair 值指定为 FairSync 或 NonFairSync。
内部嵌套类 Sync

abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 1192457210091910933L;

    // 构造器,将父类 AQS 的 state 变量初始化为给定的 permits
    Sync(int permits) {
        setState(permits);
    }

    // 非公平方式尝试获取许可(减少 state 的值)
    final int nonfairTryAcquireShared(int acquires) {
        // 自旋操作
        for (;;) {
            // 获取许可值(state),并尝试 CAS 修改为减去后的结果
            int available = getState();
            int remaining = available - acquires;
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                return remaining;
        }
    }

    // 释放许可(增加 state 的值)
    protected final boolean tryReleaseShared(int releases) {
        for (;;) {
            // 操作与获取类似,不同的在于此处是增加 state 值
            int current = getState();
            int next = current + releases;
            if (next < current) // overflow
                throw new Error("Maximum permit count exceeded");
            if (compareAndSetState(current, next))
                return true;
        }
    }

	//TODO...
}

Sync 类继承自 AQS,并重写了 AQS 的 tryReleaseShared 方法,其中获取和释放许可分别对应的是对 AQS 中 state 值的减法和加法操作。

NonFairSync (非公平版本实现)

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = -2694183684443567898L;

    // 调用父类 Sync 的构造器来实现
    NonfairSync(int permits) {
        super(permits);
    }
    // 重写 AQS 的 tryAcquireShared 方法,代码实现在父类 Sync 中
    protected int tryAcquireShared(int acquires) {
        return nonfairTryAcquireShared(acquires);
    }
}

FairSync (公平版本实现)

static final class FairSync extends Sync {
    private static final long serialVersionUID = 2014338818796000944L;

    // 构造器调用父类 Sync 的构造器来实现
    FairSync(int permits) {
        super(permits);
    }

    // 重写 AQS 的 tryAcquireShared 方法,尝试获取许可(permit)
    protected int tryAcquireShared(int acquires) {
        for (;;) {
            // 若队列中有其他线程等待,则获取失败(这就是体现“公平”的地方)
            if (hasQueuedPredecessors())
                return -1;
            // 获取当前的许可值
            int available = getState();
            // 计算剩余值
            int remaining = available - acquires;
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                return remaining;
        }
    }
}

主要方法:

// 获取一个许可(可中断)
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 release() {
    sync.releaseShared(1);
}
// 获取指定数量的许可(可中断)
public void acquire(int permits) throws InterruptedException {
    if (permits < 0) throw new IllegalArgumentException();
    sync.acquireSharedInterruptibly(permits);
}

// 获取指定数量的许可(不可中断)
public void acquireUninterruptibly(int permits) {
    if (permits < 0) throw new IllegalArgumentException();
    sync.acquireShared(permits);
}

// 尝试获取指定数量的许可
public boolean tryAcquire(int permits) {
    if (permits < 0) throw new IllegalArgumentException();
    return sync.nonfairTryAcquireShared(permits) >= 0;
}

// 尝试获取指定数量的许可(有超时等待)
public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
    throws InterruptedException {
    if (permits < 0) throw new IllegalArgumentException();
    return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
}

// 释放指定数量的许可
public void release(int permits) {
    if (permits < 0) throw new IllegalArgumentException();
    sync.releaseShared(permits);
}

Semaphore 的主要方法都是在嵌套类 FairSync 和 NonFairSync 及其父类 Sync 中实现的,内部嵌套类也是 AQS 的典型用法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值