并发编程源码解析(八)Semphore源码解析

本文详细解析了ReentrantLock、ReentrantReadWriteLock、ConcurrentHashMap和Semaphore的源码,介绍了Semaphore作为信号量在并发控制中的应用,以及公平锁与非公平锁的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前瞻 

 并发编程源码解析(一)ReentrantLock源码解析(超详细)-CSDN博客

 并发编程源码解析(二)ReentrantReadWriteLock源码解析之一写锁-CSDN博客

 并发编程源码解析(三)ReentrantReadWriteLock源码解析之一写锁-CSDN博客

并发编程源码解析(四)ConcurrentHashMap源码解析之一基础概念介绍以及散列算法讲解-CSDN博客

并发编程源码解析(五)ConcurrentHashMap源码解析之二读与写源码分析-CSDN博客

并发编程源码解析(六)ConcurrentHashMap源码解析之三并发扩容

并发编程源码解析(七)CountDownLatch 源码解析-CSDN博客

二、Semaphore 的基本介绍

        Semaphore 通常是一个计数器,用于跟踪共享资源的使用情况。当进程想要使用共享资源时,它会尝试获取 Semaphore,如果 Semaphore 的计数器为零,表示资源正在使用中,那么进程将被阻塞,直到 Semaphore 可用。

        它与 CountDownLatch 的作用区别主要在,CountDownLatch 的计数是不可回收的,而Semaphore 是可回收的;正是因为这一特性他也被广泛的应用于限流的场景当中。

三、Semaphore 的 使用

semaphore.acquire() 时信号量会将state -1;

semaphore.release() 时信号量会将state +1;

当为state == 0 是 acquire方法会被阻塞住

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class ThreadPool {
    private static final int MAX_THREADS = 10;
    private ExecutorService executor;
    private Semaphore semaphore;

    public ThreadPool() {
        executor = Executors.newFixedThreadPool(MAX_THREADS);
        semaphore = new Semaphore(MAX_THREADS);
    }

    public void submit(Runnable task) {
        try {
            semaphore.acquire();
            executor.submit(() -> {
                try {
                    task.run();
                } finally {
                    semaphore.release();
                }
            });
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}
 

四、 Semaphore 源码解析

4.1 构造方法

主要含有两个参数,一个是限制次数的,一个是控制公平锁和非公平锁;默认情况下会走非公平锁哦。

    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

4.2 acquire方法

acquire 方法调用 和 CountDownLatch 是一致的所以这篇文章当中就不重复赘述了,介绍tryAcyquire 方法 公平锁与非公平锁之间的区别。

    public void acquire() throws InterruptedException {
        //与CountDownLatch的await方法一致的
        sync.acquireSharedInterruptibly(1);
    }

    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            //上一期CountDownLatch已经讲过了,我们直接来讲解tryAcquireShared的方法
            doAcquireSharedInterruptibly(arg);
    }

4.2.1 公平锁

        // 整个方法和ReentrantLock十分的类似
        protected int tryAcquireShared(int acquires) {
            //死循环
            for (;;) {
                //检查队列当中是否有在排队的线程
                if (hasQueuedPredecessors())
                    return -1;
                //获取state
                int available = getState();
                //减小次数
                int remaining = available - acquires;
                // 如果小于0 或者 CAS 加锁成功则返回剩余次数
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

4.2.2 非公平锁

        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                // 和公平锁一模一样只是少了一个检查队列的部分
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

 公平锁和非公平锁十分相似,只是公平锁多了一个检查队列中是否含有线程这一方法,来保证锁的公平性;他们与之间ReentrantLock的公平锁与非公平锁的逻辑也十分相似。

4.3 release方法 

        这块逻辑比较简单,除了验证参数之外,就是单纯的使用CAS去变更了state的大小就没有其他操作了。

    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");
                //CAS 尝试变更状态;直到返回成功为止
                if (compareAndSetState(current, next))
                    return true;
            }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值