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 讲解就结束了,希望朋友们能领悟一些知识。
posted @   47号Gamer丶  阅读(168)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示