Semaphore
简介
Semaphore是一个计数信号量,它的本质是一个"共享锁"。
信号量维护了一个信号量许可集。线程可以通过调用acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。 线程可以通过release()来释放它所持有的信号量许可。
方法列表
// 创建具有给定的许可数和非公平的公平设置的 Semaphore。
Semaphore(int permits)
// 创建具有给定的许可数和给定的公平设置的 Semaphore。
Semaphore(int permits, boolean fair)
// 从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,或者线程被中断。
void acquire()
// 从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,或者线程已被中断。
void acquire(int permits)
// 从此信号量中获取许可,在有可用的许可前将其阻塞。
void acquireUninterruptibly()
// 从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。
void acquireUninterruptibly(int permits)
// 返回此信号量中当前可用的许可数。
int availablePermits()
// 获取并返回立即可用的所有许可。
int drainPermits()
// 返回一个 collection,包含可能等待获取的线程。
protected Collection<Thread> getQueuedThreads()
// 返回正在等待获取的线程的估计数目。
int getQueueLength()
// 查询是否有线程正在等待获取。
boolean hasQueuedThreads()
// 如果此信号量的公平设置为 true,则返回 true。
boolean isFair()
// 根据指定的缩减量减小可用许可的数目。
protected void reducePermits(int reduction)
// 释放一个许可,将其返回给信号量。
void release()
// 释放给定数目的许可,将其返回到信号量。
void release(int permits)
// 返回标识此信号量的字符串,以及信号量的状态。
String toString()
// 仅在调用时此信号量存在一个可用许可,才从信号量获取许可。
boolean tryAcquire()
// 仅在调用时此信号量中有给定数目的许可时,才从此信号量中获取这些许可。
boolean tryAcquire(int permits)
// 如果在给定的等待时间内此信号量有可用的所有许可,并且当前线程未被中断,则从此信号量获取给定数目的许可。
boolean tryAcquire(int permits, long timeout, TimeUnit unit)
// 如果在给定的等待时间内,此信号量有可用的许可并且当前线程未被中断,则从此信号量获取一个许可。
boolean tryAcquire(long timeout, TimeUnit unit)
个人理解
Semaphore信号量 个人理解成一个许可证池(初始数量允许<0)
关键操作
当调用acquire()时 若剩余的许可证数量能满足需求是 立即返回 否则 持续等待 直到许可数量满足该线程要求的许可数量
调用drainPermits()将清空当前Semaphore的数量 将数量置为0 同时返回清空的许可证数量
调用release(permits) 将往Semaphore的许可证池增加permits数量 permits不允许为负 默认为1
调用acquire(?)和acquireUninterruptibly(?)的区别是 acquire允许被线程打断而acquireUninterruptibly不允许
调用acquire(?)和tryAcquire(?)的区别是tryAcquire是立即返回 返回结果是当许可证足够时返回true,否则返回false
调用tryAcquire(?)和tryAcquire(?TimeUtil...)的区别是tryAcquire(?TimeUtil...)当未获取到足够的许可时会尝试等待一段时间继续尝试获取
构造方法默认创建一个非公平Semaphore 其中公平和非公平的区别在于 公平的要求等候的线程先进先出(队列模型),而非公平的只要当前剩余的许可需求能被满足,就交给获取的线程(先满足能满足的)
使用场景
刚接触Semaphore的时候,同事举了个蹲坑的栗子:
Semaphore semaphore = new Semaphore(5);
AtomicInteger ai = new AtomicInteger();
for (int i = 0; i < 10; i++) {
new Thread(
()->{
try {
int num = ai.incrementAndGet();
long t1 = System.currentTimeMillis();
semaphore.acquire();
long t2 = System.currentTimeMillis();
System.out.println(String.format("people%s 占到坑 等待时间:%sms, 开始享受...", num,(t2-t1)));
Thread.sleep(500+new Random().nextInt(500));
long t3 = System.currentTimeMillis();
System.out.println(String.format("people%s 使用完毕 总共耗时:%sms, 离开...", num, (t3-t2)));
semaphore.release();
} catch (Exception e) {
e.printStackTrace();
}
}
).start();
}
people5 占到坑 等待时间:0ms, 开始享受...
people4 占到坑 等待时间:0ms, 开始享受...
people1 占到坑 等待时间:0ms, 开始享受...
people3 占到坑 等待时间:0ms, 开始享受...
people2 占到坑 等待时间:0ms, 开始享受...
people2 使用完毕 总共耗时:539ms, 离开...
people6 占到坑 等待时间:538ms, 开始享受...
people1 使用完毕 总共耗时:598ms, 离开...
people7 占到坑 等待时间:597ms, 开始享受...
people3 使用完毕 总共耗时:697ms, 离开...
people8 占到坑 等待时间:696ms, 开始享受...
people5 使用完毕 总共耗时:714ms, 离开...
people9 占到坑 等待时间:714ms, 开始享受...
people4 使用完毕 总共耗时:997ms, 离开...
people10 占到坑 等待时间:997ms, 开始享受...
people6 使用完毕 总共耗时:563ms, 离开...
people7 使用完毕 总共耗时:751ms, 离开...
people9 使用完毕 总共耗时:716ms, 离开...
people10 使用完毕 总共耗时:554ms, 离开...
people8 使用完毕 总共耗时:885ms, 离开...
示例代码(java 1.8)
Semaphore s = new Semaphore(10, true);//公平
//Semaphore s = new Semaphore(10);//非公平
List<Integer> list = Arrays.asList(3,4,7,2);
list.forEach(i->{
new Thread(()->{
System.out.println(String.format("runner:%s wait for begin...", i));
try {
s.acquire(i);
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}finally{
s.release(i);
}
System.out.println(String.format("runner:%s wait over...", i));
}).start();
try {
Thread.sleep(50);
} catch (Exception e2) {
}
});
输出结果
公平semaphore输出结果
runner:3 wait for begin...
runner:4 wait for begin...
runner:7 wait for begin...
runner:2 wait for begin...
runner:3 wait over...
runner:4 wait over...
runner:7 wait over...
runner:2 wait over...
非公平semaphore输出结果
runner:3 wait for begin...
runner:4 wait for begin...
runner:7 wait for begin...
runner:2 wait for begin...
runner:3 wait over...
runner:4 wait over...
runner:2 wait over...
runner:7 wait over...