闲谈一下 Semaphore

Semaphore 在项目中使用很少,直到我读了一个开源项目,原来 Semaphore 可以被恰当地使用的。

一、Semaphore 简介

Semaphore(信号量)是一种计数器,用于限制同时访问特定资源或执行某段代码的线程数量。

它内部维护了一个许可的数量,每当一个线程进入需要被保护的代码块时,就尝试获取一个许可或者多个;当离开这个代码块时,则释放该许可。

如果所有许可都被占用,那么新请求许可的线程将等待。

Semaphore信号量与 CountDownLatch 不同的是,它内部的计数器是递增的,并且在一开始初始化允许的最大值。

二、初识 Semaphore

第一次正式认识 Semaphore 还是在一款开源软件上。

项目地址:java-log-producer: 阿里云 java-log-producer (fork到自己的仓库了)

项目简单介绍: Aliyun LOG Java Producer 是一个易于使用且高度可配置的 Java 类库,专门为运行在大数据、高并发场景下的 Java 应用量身打造。

2.1 Semaphore 的用途

用于控制可用空间大小,类似于限流。 在这个开源软件它是这么使用的:

类的位置:com.aliyun.openservices.aliyun.log.producer.LogProducer

memoryController 用于控制当前机器中正在发送中的日志内存总大小。

com.aliyun.openservices.aliyun.log.producer.internals.LogAccumulator

在这段逻辑中, 由于发送的日志是并发的,为了防止发送占用内存过大, Semaphore 类型的变量 memoryController,用于控制正在发送的内存总大小。

简而言之:限流,限制发送日志的内存占用量。

三、Semaphore 使用注意事项

Semaphore调用acquire()获取许可, try ... finallyfinally中释放许可。通常建议放在 finally 代码块中。

调用acquire()可能会进入等待,直到满足条件为止。也可以使用tryAcquire()指定等待时间:

另外:避免线程等待,可以设置最长等待时长。

获取许可不允许设置负数。

public boolean tryAcquire(int permits) {
    if (permits < 0) throw new IllegalArgumentException();
    return sync.nonfairTryAcquireShared(permits) >= 0;
}

四、应用场景

根据 Semaphore 的特性,可以围绕 “限流” 场景,进行合理的落地。(注意是虚拟机级别的,非分布式)

五、Semaphore 内部结构

Semaphore的核心在于其内部类Sync,它继承自AbstractQueuedSynchronizer(AQS),这是其核心。Sync类通过getState()setState(int newState)方法管理许可数量。

  • 非公平模式NonfairSync类通过nonfairTryAcquireShared(int acquires)nonfairTryReleaseShared(int releases)方法实现许可的获取和释放,这种方式下,线程的调度可能不是公平的。
  • 公平模式FairSync类通过tryAcquireShared(int acquires)tryReleaseShared(int releases)方法实现许可的获取和释放,这种方式下,线程调度是公平的,即按照线程等待的顺序来分配许可。

默认是:非公平模式

 public Semaphore(int permits) {
        sync = new NonfairSync(permits);
 }

公平策略: 看当前线程节点的前驱节点是否也在等待获取该资源,如果是则放弃获取的权限,然后加入 AQS 阻塞队列,否则就直接获取。

六、总结

Semaphore 跟 CountDownLatch 一样,都复用 AQS 的能力。 另外都使用for(;;) 自旋 ,compareAndSetState 对 state 进行安全操作

整体上而言,Semaphore 在使用限流上经常被其他工具所替代,比如 guava#Ratelimiter 限流工具。所以在使用上不多。感兴趣可以再深入挖掘。

已同步发布微信公众号:面汤放盐 闲谈一下 Semaphore

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值