JUC-Semaphore使用及原理分析

博客介绍了Java中Semaphore类,它是基于AQS实现的计数信号量,用于限制访问资源的线程数目。以停车场为例展示其使用,同一时刻最多容纳指定数量线程。还对其源码进行分析,包括初始化时对state赋值,acquire方法获取资源,release方法释放资源并唤醒等待线程。

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

1 Semaphore简介及使用

ps:要想理解Semaphore原理,需要先了解AQS,不了解AQS的可以看先之前的文章->aqs源码解析

Semaphore类是一个计数信号量,必须由获取它的线程释放,底层是基于AQS实现的,通常用于限制可以访问某些资源(物理或逻辑的)线程数目。

举个例子,某个停车场总共有5个停车位,意味着同一时刻最多只能容纳5辆车,先来的5辆车占了车位之后,其他的车只能等待或者离开。下面是代码演示:

public class SemaphoreDemo {

    public static void main(String[] args) {
    	// 初始化 相当于5个车位
        Semaphore semaphore = new Semaphore(5);
        // 10辆车同时抢占车位
        for (int i=0; i<10; i++){
            new Car(i, semaphore).start();
        }
    }

    static class Car extends Thread{

        private Integer num;

        private Semaphore semaphore;

        public Car(Integer num, Semaphore semaphore){
            this.num = num;
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println("第" + num +"辆车 抢占一个车位 ");
                TimeUnit.SECONDS.sleep(1);
                System.out.println("第" + num +"辆车 开走了 ");
                semaphore.release();
            }catch (InterruptedException e){

            }
        }
    }

}

运行结果:
在这里插入图片描述
同一时刻最多容纳5辆车,当车位释放时,才可以有新的车去抢占车位。

2 源码分析

2.1 Semaphore初始化

		Sync(int permits) {
            setState(permits);
        }

当通过构造初始化的时候,调用setState对state变量进行赋值,这个state相当于车位数(限流数)

2.2 acquire方法

	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);
    }
    
	final int nonfairTryAcquireShared(int acquires) {
         for (;;) {
         	// 获取限流数
             int available = getState();
             // 可用车位 - 本次获取车位 = 剩余可用车位
             int remaining = available - acquires;
             if (remaining < 0 ||
             	 // cas方式对变量进行修改
                 compareAndSetState(available, remaining))
                 return remaining;
         }
     }

调用acquire方法,默认每次值获取一个共享资源(相当于车位),通过自旋 + cas的方式,修改剩余可用共享资源的个数。

2.3 release方法

	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) {
		// 自旋 + cas 的方式修改资源数
        for (;;) {
        	  // 获取当前state
              int current = getState();
              // 基数本次释放后 state的值
              int next = current + releases;
              if (next < current) // overflow
                  throw new Error("Maximum permit count exceeded");
              // 修改
              if (compareAndSetState(current, next))
                  return true;
          }
      }

调用release方法进行释放资源,通过修改state的值进行释放资源,如果释放成功后,唤醒等待队列中的线程去竞争资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值