辅助类-Semaphore
概述
顾名思义,就是信号灯,可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源。
其主要有几个方法
| 方法 | 描述 |
|---|---|
| acquire() | 获取一个令牌,在获取到令牌、或者被其他线程调用中断之前线程一直处于阻塞状态。 |
| acquire(int permits) | 从这个信号量获取给定数量的许可,阻塞直到所有许可都可用,或者线程被中断 |
| acquireUninterruptibly() | 获取一个令牌,在获取到令牌之前线程一直处于阻塞状态(忽略中断)。 |
| tryAcquire() | 尝试获得令牌,返回获取令牌成功或失败,不阻塞线程。 |
| tryAcquire(long timeout, TimeUnit unit) | 尝试获得令牌,在超时时间内循环尝试获取,直到尝试获取成功或超时返回,不阻塞线程。 |
| release() | 释放一个令牌,唤醒一个获取令牌不成功的阻塞线程。 |
| hasQueuedThreads() | 等待队列里是否还存在等待线程。 |
| getQueueLength() | 获取等待队列里阻塞的线程数。 |
| drainPermits() | 清空令牌把可用令牌数置为0,返回清空令牌的数量。 |
| availablePermits() | 返回可用的令牌数量。 |
什么意思?我们来看一个应用
例子
我们现在有一个餐厅,有客人来餐厅吃饭,但是餐厅的桌位有限,我们来看一下怎么实现
public class Restaurant {
public static void main(String[] args) {
//创建一个Semaphore对象,设置permits为3,代表餐厅有3个桌位
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 6; ++i) {
new Thread(() -> {
try {
//获取一个令牌,等于用户拿到位置
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "拿到了位置");
System.out.println("---" + Thread.currentThread().getName() + "用完餐了,离开了位置");
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
//释放一个令牌,等于用户用完餐后离开位置
semaphore.release();
}
}, "用户" + i).start();
}
}
}
看一下执行的结果
用户0拿到了位置
用户1拿到了位置
---用户1用完餐了,离开了位置
---用户0用完餐了,离开了位置
用户2拿到了位置
---用户2用完餐了,离开了位置
用户3拿到了位置
---用户3用完餐了,离开了位置
用户4拿到了位置
---用户4用完餐了,离开了位置
用户5拿到了位置
---用户5用完餐了,离开了位置
进程已结束,退出代码0
注意:
-
当调用new Semaphore(3) 方法时,默认会创建一个非公平的锁的同步阻塞队列,之后如果令牌数量不足,则会创建一个Node节点加入阻塞队列,挂起当前线程
-
释放令牌不会唤醒所有的节点,只是将队列中的第一个需要唤醒的线程进行唤醒
这就是这篇文章的内容了,欢迎大家的讨论,如有错漏,也请指出,谢谢~