AQS源码解读(九)——Semaphore信号量原理详解

本文详细介绍了Java中的Semaphore信号量概念,其在并发控制中的应用,包括公平锁与非公平锁的区别,以及Semaphore的获取和释放资源许可的方法。通过实例代码展示了如何在实际场景中使用Semaphore。结尾部分强调了主动学习的重要性。
摘要由CSDN通过智能技术生成

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

    • 前言
  • 代码示例

  • Semaphore基本结构

  • 获取资源许可

    • tryAcquireShared
    • Semaphore.NonfairSync#tryAcquireShared
  • Semaphore.FairSync#tryAcquireShared

  • 释放资源许可

    • Semaphore.Sync#tryReleaseShared
  • 资源许可清零Semaphore#drainPermits

  • 总结

前言


Semaphore翻译是信号量的意思,可以控制并发访问资源的数量。

Semaphore semaphore = new Semaphore(10); //初始化一个信号桶,也可以叫令牌桶,里面有10个资源许可

semaphore.acquire();//获取一个资源许可

semaphore.release();//释放一个资源许可

10个资源许可被取完后,再来线程获取就会入队列阻塞。

Semaphore是在AQS基础上实现的共享锁,获取资源和释放资源都是调用的AQS中共享锁模板方法,故只需要看tryAcquireSharedtryReleaseSharedSemaphore中的实现。

代码示例


首先初始化Semaphore,给资源许可5个,模拟多个线程获取资源。

public class Test1072 {

private static Semaphore semaphore = new Semaphore(5);

public static void main(String[] args) {

for (int i = 0; i < 10; i++) {

Thread thread = new Thread(new MyThread(i));

thread.start();

}

}

static class MyThread implements Runnable{

private int i;

public MyThread(int i) {

this.i = i;

}

@Override

public void run() {

try {

semaphore.acquire();

System.out.println(Thread.currentThread().getName() + “, semaphore.acquire()获取资源–” + i);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

// System.out.println(Thread.currentThread().getName() + “,semaphore.release()释放资源–” + i);

// semaphore.release();

}

}

}

}

//控制台输出

//线程只获取资源不释放

Thread-0, semaphore.acquire()获取资源–0

Thread-1, semaphore.acquire()获取资源–1

Thread-2, semaphore.acquire()获取资源–2

Thread-6, semaphore.acquire()获取资源–6

Thread-3, semaphore.acquire()获取资源–3

//线程获取资源并释放资源

Thread-0, semaphore.acquire()获取资源–0

Thread-2, semaphore.acquire()获取资源–2

Thread-2,semaphore.release()释放资源–2

Thread-1, semaphore.acquire()获取资源–1

Thread-1,semaphore.release()释放资源–1

Thread-0,semaphore.release()释放资源–0

Thread-3, semaphore.acquire()获取资源–3

Thread-3,semaphore.release()释放资源–3

Thread-5, semaphore.acquire()获取资源–5

Thread-5,semaphore.release()释放资源–5

Thread-4, semaphore.acquire()获取资源–4

Thread-4,semaphore.release()释放资源–4

Thread-6, semaphore.acquire()获取资源–6

Thread-6,semaphore.release()释放资源–6

Thread-7, semaphore.acquire()获取资源–7

Thread-7,semaphore.release()释放资源–7

Thread-9, semaphore.acquire()获取资源–9

Thread-9,semaphore.release()释放资源–9

Thread-8, semaphore.acquire()获取资源–8

Thread-8,semaphore.release()释放资源–8

在没有释放资源前,只有五个线程可以获取资源,其他线程都进入队列阻塞。当线程获取资源,执行完业务代码释放资源,则每个线程都可以获取资源,无需阻塞。

Semaphore基本结构


Semaphore中也有一个内部类SyncSync继承自AbstractQueuedSynchronizer,所以核心代码都在Sync中。从构造函数看出,Sync还有两个子类NonfairSyncFairSync,说明Semaphore实现的共享锁区分公平性。

public class Semaphore implements java.io.Serializable {

private static final long serialVersionUID = -3222578661600680210L;

/** All mechanics via AbstractQueuedSynchronizer subclass */

private final Sync sync;

/**

  • Synchronization implementation for semaphore. Uses AQS state

  • to represent permits. Subclassed into fair and nonfair

  • versions.

*/

abstract static class Sync extends AbstractQueuedSynchronizer {

… …

}

public Semaphore(int permits) {

sync = new NonfairSync(permits);

}

public Semaphore(int permits, boolean fair) {

sync = fair ? new FairSync(permits) : new NonfairSync(permits);

}

}

获取资源许可


Semaphore提供了可中断获取资源许可(Semaphore#acquire()),不可中断获取资源许可(Semaphore#acquireUninterruptibly()),尝试获取资源许可(Semaphore#tryAcquire()),超时可中断获取资源许可(Semaphore#tryAcquire(long, java.util.concurrent.TimeUnit))。底层代码调用的都是AQS中共享模式获取锁的模板方法,故只需要看看tryAcquireSharedSemaphore中的实现。

//1.可中断获取资源许可

public void acquire() throws InterruptedException {

sync.acquireSharedInterruptibly(1);

}

//2.可中断获取permits个资源许可

public void acquire(int permits) throws InterruptedException {

if (permits < 0) throw new IllegalArgumentException();

sync.acquireSharedInterruptibly(permits);

}

//3.不可中断获取资源许可

public void acquireUninterruptibly() {

sync.acquireShared(1);

}

//4.不可中断获取permits个资源许可

public void acquireUninterruptibly(int permits) {

if (permits < 0) throw new IllegalArgumentException();

sync.acquireShared(permits);

}

//5.尝试获取资源许可,获取成功返回true

public boolean tryAcquire() {

return sync.nonfairTryAcquireShared(1) >= 0;

}

//6.尝试获取permits个资源许可,获取成功返回true

public boolean tryAcquire(int permits) {

if (permits < 0) throw new IllegalArgumentException();

return sync.nonfairTryAcquireShared(permits) >= 0;

}

//7.超时可中断获取资源许可,获取失败进入队列阻塞一段时间,超时还未获取返回false

public boolean tryAcquire(long timeout, TimeUnit unit)

throws InterruptedException {

return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));

}

//8.超时可中断获取permits个资源许可,获取失败进入队列阻塞一段时间,超时还未获取返回false

public boolean tryAcquire(int permits, long timeout, TimeUnit unit)

throws InterruptedException {

if (permits < 0) throw new IllegalArgumentException();

return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));

}

tryAcquireShared

Semaphore中获取资源许可有公平锁和非公平锁之分。

Semaphore.NonfairSync#tryAcquireShared

NonfairSync中的tryAcquireShared调用了Semaphore.Sync中已经实现好的nonfairTryAcquireShared

static final class NonfairSync extends Sync {

private static final long serialVersionUID = -2694183684443567898L;

NonfairSync(int permits) {

super(permits);

}

protected int tryAcquireShared(int acquires) {

return nonfairTryAcquireShared(acquires);

}

}

获取资源许可,就是对state做减法,remaining =当前许可量—获取的许可量,remaining >= 0即可以CAS修改state资源许可数,获取成功返回remaining资源许可剩余量。CAS修改state失败会不断自旋。

//java.util.concurrent.Semaphore.Sync#nonfairTryAcquireShared

final int nonfairTryAcquireShared(int acquires) {

for (;😉 {

//获取可用资源许可量

int available = getState();

//计算可用资源许可剩余量

int remaining = available - acquires;

//remaining <0 说明资源许可耗尽

//remaining >= 0 可继续获取资源许可cas

if (remaining < 0 ||

compareAndSetState(available, remaining))

//返回剩余许可量

return remaining;

}

}

写在最后

很多人感叹“学习无用”,实际上之所以产生无用论,是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。

最后祝愿各位身体健康,顺利拿到心仪的offer!

由于文章的篇幅有限,所以这次的蚂蚁金服和京东面试题答案整理在了PDF文档里

蚂蚁、京东Java岗4面:原理+索引+底层+分布式+优化等,已拿offer

蚂蚁、京东Java岗4面:原理+索引+底层+分布式+优化等,已拿offer

蚂蚁、京东Java岗4面:原理+索引+底层+分布式+优化等,已拿offer
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!
ining;

}

}

写在最后

很多人感叹“学习无用”,实际上之所以产生无用论,是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。

最后祝愿各位身体健康,顺利拿到心仪的offer!

由于文章的篇幅有限,所以这次的蚂蚁金服和京东面试题答案整理在了PDF文档里

[外链图片转存中…(img-Jbe5RFps-1714467456083)]

[外链图片转存中…(img-Ay9OQKia-1714467456083)]

[外链图片转存中…(img-0OVlNLpa-1714467456084)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值