Semaphore用例、源码分析讲解
semaphore 也就是我们常说的信号灯,semaphore 可以控制同时访问的线程个数,通过 acquire 获取一个许可,如果没有就等待,通过 release 释放一个许可。有点类似限流的作用。叫信号灯的原因也和他的用处有关,比如某商场就 5 个停车位,每个停车位只能停一辆车,如果这个时候来了 10 辆车,必须要等前面有空的车位才能进入。
使用案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public static void main(String[] args) { Semaphore semaphore= new Semaphore( 5 ); for ( int i= 0 ;i< 10 ;i++){ new Car(i,semaphore).start(); } } static class Car extends Thread{ private int num; private Semaphore semaphore; public Car( int num, Semaphore semaphore) { this .num = num; this .semaphore = semaphore; } public void run(){ try { semaphore.acquire(); //获取一个许可 System.out.println( "第" +num+ "占用一个停车位" ); TimeUnit.SECONDS.sleep( 2 ); System.out.println( "第" +num+ "俩车走喽" ); semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } } } |
使用场景
Semaphore 比较常见的就是用来做限流操作了。
Semaphore 源码分析
从 Semaphore 的功能来看,我们基本能猜测到它的底层实现一定是基于 AQS 的共享所,因为需要实现多个线程共享一个领排池创建 Semaphore 实例的时候,需要一个参数 permits,这个基本上可以确定是设置给 AQS 的 state 的,然后每个线程调用 acquire 的时候,行 state = state - 1,release 的时候执行 state = state + 1,当然,acquire 的时候,如果 state = 0,说明没有资源了,需要等待其他线程 release。
Semaphore 分公平策略和非公平策略 :
FairSync:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | static final class FairSync extends Sync { private static final long serialVersionUID = 2014338818796000944L; FairSync( int permits) { super (permits); } protected int tryAcquireShared( int acquires) { for (; ; ) { // 区别就在于是不是会先判断是否有线程在排队,然后才进行 CAS 减操作 if (hasQueuedPredecessors()) return - 1 ; int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } } } |
NofairSync :
通过对比发现公平和非公平的区别就在于是否多了一个hasQueuedPredecessors 的判断。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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); } } final int nonfairTryAcquireShared( int acquires) { for (; ; ) { int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } } |
由于后面的代码和 CountDownLatch 的是完全一样,都是基于共享锁的实现,所以也就没必要再花时间来分析了。
至此,Semaphore 讲解就结束了,希望朋友们能领悟一些知识。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具