【Java并发】 - Semaphore

本文详细介绍了Semaphore的概念及使用方式,包括如何限制资源访问线程的数量,并通过示例代码展示了Semaphore的基本用法,以及drainPermits方法的使用。

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

概述

Semaphore(信号量),通常用于限制某些资源的访问线程数量。通过调用aquire方法获取许可,没有获取到许可则阻塞当前线程直到获取到许可为止。操作完成后通过调用release方法来释放许可,从而允许其他线程去获取许可。同时Semaphore也支持超时的获取方式。
从描述来看这基本和AQS的原理和使用方式如出一辙,只是将同步状态设置了一个上界。

使用

假设一个教室只允许5个学生进入,当教室满了之后其他想进入的学生只能等待某个学生出来才能进入。
public class SemaphoreDemo {
	
	public static void main(String[] args) throws InterruptedException {
		
		Semaphore semaphore = new Semaphore(5);
		
		for (int i = 0; i < 10; i++){
			final int num = i;
			Thread t = new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						semaphore.acquire();
						System.out.println("student" + num + " got in");
						Thread.sleep(1000);
						System.out.println("student" + num + " got out");
						semaphore.release();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
			t.start();
			//为了使前五个线程不在同一时间点结束
			Thread.sleep(100);
		}
	}
}


输出结果:

student0 got in
student1 got in
student2 got in
student3 got in
student4 got in
student0 got out
student5 got in
student1 got out
student6 got in
student2 got out
student7 got in
student3 got out
student8 got in
student4 got out
student9 got in
student5 got out
student6 got out
student7 got out
student8 got out
student9 got out

实现原理

Semaphore的结构



看Semaphore的目录结构就基本可以明白Semaphore的实现基本也是通过AQS初始化一个state,并通过获取同步状态和释放同步状态的方式去控制访问量,如果tryAquire方方法失败意味着获取许可失败,此时AQS将挂起当前的线程。同时调用release来释放同步状态。
实现方式基本比较简单,同时还支持了公平和非公平的选择。

值得注意的是Semaphore还提供了一个drainPermits方法,作用是获取并返回立即可用的所有许可。
例子:
public class SemaphoreDemo {
	
	public static void main(String[] args) throws InterruptedException {
		
		Semaphore semaphore = new Semaphore(5);
		
		for (int i = 0; i < 10; i++){
			final int num = i;
			Thread t = new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						if (num == 3)
							semaphore.drainPermits();
						semaphore.acquire();
						System.out.println("student" + num + " got in");
						Thread.sleep(1000);
						System.out.println("student" + num + " got out");
						semaphore.release();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
			t.start();
			//为了使前五个线程不在同一时间点结束
			Thread.sleep(100);
		}
	}
}

在第四次获取之前将剩下的许可全部获取
输出:
student0 got in
student1 got in
student2 got in
student0 got out
student3 got in
student1 got out
student4 got in
student2 got out
student5 got in
student3 got out
student6 got in
student4 got out
student7 got in
student5 got out
student8 got in
student6 got out
student9 got in
student7 got out
student8 got out
student9 got out

源码:
final int drainPermits() {
    for (;;) {
        int current = getState();
        if (current == 0 || compareAndSetState(current, 0))
            return current;
    }
}

自旋+CAS的方式将同步状态设置为0(即没有可用许可的状态)













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值