Semaphore源码剖析

Semaphore源码剖析

Semaphore从英⽂单词上翻译是:信号量,可以理解 他是⼀个 许可证。只有获取到 许可证 的线程,才能执⾏相应逻辑,同时拿⾛ 许可证,⽽那些没有获取到的线程 只能等待。当持有 许可证 的线程 执⾏完成 后,需要 归还 许可证, 下⼀个线程 才可以 获取 许可证 执⾏相应逻辑。

测试案例:

public class SemaphoreDemo {

    public static void main(String[] args) {
        SemaphoreDemo demo = new SemaphoreDemo();
        demo.test();
    }

    private void test() {
        // 停车场同时容纳的车辆 5
        Semaphore semaphore = new Semaphore(5);
        List<Thread> threadList = new ArrayList<>();
        // 模拟 8 辆车进入停车场
        for (int i = 0; i < 8; i++) {
            threadList.add(new Thread(() -> this.park(semaphore)));
        }
        threadList.forEach(Thread::start);
    }

    private void park(Semaphore semaphore) {
        try {
            Random random = new Random();
            int seconds = random.nextInt(4) + 2;
            System.out.println(Thread.currentThread().getName() + " --> 来到停车场");
            if (semaphore.availablePermits() == 0) {
                System.err.println(Thread.currentThread().getName() + " --> 车位不足,请耐心等待");
            }
            semaphore.acquire();// 获取令牌尝试进入停车场
            System.out.println(Thread.currentThread().getName() + " --> 成功进入停车场 停留时间 [" + seconds + "] 秒");
            Thread.sleep(seconds * 1000);
            System.out.println(Thread.currentThread().getName() + " --> 驶出停车场");
            semaphore.release();//释放令牌,腾出停车场车位
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

Thread-3 --> 来到停车场
Thread-4 --> 来到停车场
Thread-0 --> 来到停车场
Thread-2 --> 来到停车场
Thread-5 --> 来到停车场
Thread-1 --> 来到停车场
Thread-7 --> 来到停车场
Thread-6 --> 来到停车场
Thread-3 --> 成功进入停车场 停留时间 [2]Thread-7 --> 成功进入停车场 停留时间 [3]Thread-4 --> 成功进入停车场 停留时间 [2]Thread-1 --> 成功进入停车场 停留时间 [4]Thread-2 --> 成功进入停车场 停留时间 [4]Thread-6 --> 车位不足,请耐心等待
Thread-4 --> 驶出停车场
Thread-3 --> 驶出停车场
Thread-5 --> 成功进入停车场 停留时间 [5]Thread-6 --> 成功进入停车场 停留时间 [2]Thread-7 --> 驶出停车场
Thread-0 --> 成功进入停车场 停留时间 [2]Thread-2 --> 驶出停车场
Thread-6 --> 驶出停车场
Thread-1 --> 驶出停车场
Thread-0 --> 驶出停车场
Thread-5 --> 驶出停车场

常用方法源码剖析:

public class Semaphore implements java.io.Serializable {
	private final Sync sync;
	
    abstract static class Sync extends AbstractQueuedSynchronizer {
        .....
    }
    
    // permits:表示允许同时执行任务的线程个数,
    // 底层其实是给aqs的state变量进行赋值
    public Semaphore(int permits) {
        // 默认使用非公平锁
        sync = new NonfairSync(permits);
    }
    
    // 同上,fair=true时,使用公平锁
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }
    
    // 查看是否有可用的令牌
    public int availablePermits() {
        return sync.getPermits();// 底层就是直接获取的aqs的state的值
    }
    
    // 获取令牌
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    
    // 见读写锁该方法的解析
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
    
    // 公平锁实现
    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;
        }
    }
    // 非公平锁实现
    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;
        }
    }
    
    // 释放令牌
    public void release() {
        sync.releaseShared(1);
    }
    
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }
    
    protected final boolean tryReleaseShared(int releases) {
        for (;;) {
            int current = getState();
            int next = current + releases;
            if (next < current) // overflow
                throw new Error("Maximum permit count exceeded");
            if (compareAndSetState(current, next))
                return true;
        }
    }

}

总结:Semaphore底层其实还是基于AQS的state变量来进行操作的。

posted on   ~码铃薯~  阅读(9)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
历史上的今天:
2022-09-02 参数多态、过载多态、包含多态、强制多态
2021-09-02 访问者模式

导航

< 2025年3月 >
23 24 25 26 27 28 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 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示