Semaphore概述
首先我们看一下官方给出该工具的定义👇👇👇
A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each acquire() blocks if necessary until a permit is available, and then takes it. Each release() adds a permit, potentially releasing a blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the number available and acts accordingly.
Semaphores are often used to restrict the number of threads than can access some (physical or logical) resource.
简单来说:
1.Semaphore通过初始化维护了一组凭证,通过acquire()获取凭证否则会阻塞,执行完动作后,通过release()释放手中的凭证供下一个工作线程使用。
2.Semaphore通常用于限制可以访问某些资源的线程数。
3.Semaphore是一个计数器,并且计数可以重复使用,获取凭证释放凭证。
Semaphore实战之访问控制
狗哥一直想自己创业,经过一段时间的努力,每月把女朋友们的工资都攒下,终于有了本金,由于女朋友按摩手法相当了得,狗哥本着造福大众,有福同享,有钱我赚的思想决定开一家正规按摩店💆💆💆。
这就遇到个问题,只有三个女朋友的狗哥,同时只能接待三位客人,狗哥就在想啊,这怎么解决客人多了的按摩问题呢。想来想去只能进行限流,也不能让一个女朋友同时给多个客人按摩吧😰😰
于是狗哥就设置了三个按摩凭证,客人拿到凭证后呢,就可以进房间享受按摩服务,出来之后再把凭证交还给狗哥保管。
这时候有的客人就说了,我不想排队,我有钱能插队不。狗哥不是为了钱,只是为了满足客人的要求,又提出了周一到周五按排队顺序提供凭证,而周末则是价高者先得。
这个需求怎么做呢,本质上是个流量控制,每次仅允许三位拿到凭证的客人进行按摩,按摩后交还凭证后下一位客人可以继续。还有个需要考虑的点就是获取凭证的公平及非公平的问题。是不是有点思路了?
package com.cn.scott.test;
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
static class Customer implements Runnable {
private Semaphore semaphore;
private Integer order;
Customer(Integer order, Semaphore semaphore) {
this.order = order;
this.semaphore = semaphore;
}
@Override
public void run() {
String customerName = "客户" + order;
System.out.println(customerName + "正在排队等待...");
try {
semaphore.acquire();
System.out.println(customerName + "获取门票并且开始按摩");
Thread.sleep(order * 1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
System.out.println(customerName + "按摩完毕,即将归还门票");
semaphore.release();
}
}
}
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 5; i++) {
new Thread(new Customer(i, semaphore)).start();
}
}
}
执行结果如下:
客户1正在排队等待…
客户4正在排队等待…
客户1获取门票并且开始按摩
客户2正在排队等待…
客户2获取门票并且开始按摩
客户3正在排队等待…
客户5正在排队等待…
客户4获取门票并且开始按摩
客户1按摩完毕,即将归还门票
客户3获取门票并且开始按摩
客户2按摩完毕,即将归还门票
客户5获取门票并且开始按摩
客户4按摩完毕,即将归还门票
客户3按摩完毕,即将归还门票
客户5按摩完毕,即将归还门票
当我们想按顺序获取门票并进行按摩的时候,我们需要调用Semaphore的另外一个构造,代码如下👇👇:
Semaphore semaphore1 = new Semaphore(3,true);
for (int i = 1; i <= 5; i++) {
new Thread(new Customer(i,semaphore1)).start();
}
按排队顺序公平按摩的结果如下👇👇:
客户1正在排队等待…
客户3正在排队等待…
客户2正在排队等待…
客户2获取门票并且开始按摩
客户3获取门票并且开始按摩
客户4正在排队等待…
客户1获取门票并且开始按摩
客户5正在排队等待…
客户1按摩完毕,即将归还门票
客户4获取门票并且开始按摩
客户2按摩完毕,即将归还门票
客户5获取门票并且开始按摩
客户3按摩完毕,即将归还门票
客户4按摩完毕,即将归还门票
客户5按摩完毕,即将归还门票
从执行结果不难看出我们已经实现了上述需求。接下来我们看看Semaphore提供的其他方法。
方法 | 说明 |
---|---|
acquire() | 从信号量获取一个许可,如果无可用许可前将一直阻塞等待 |
acquire(int permits) | 获取指定数目的许可,如果无可用许可前也将会一直阻塞等待 |
tryAcquire() | 从信号量尝试获取一个许可,如果无可用许可,直接返回false,不会阻塞 |
tryAcquire(int permits) | 尝试获取指定数目的许可,如果无可用许可直接返回false |
tryAcquire(int permits, long timeout, TimeUnit unit) | 在指定的时间内尝试从信号量中获取许可,如果在指定的时间内获取成功,返回true,否则返回false |
release() | 释放一个许可,别忘了在finally中使用,注意:多次调用该方法,会使信号量的许可数增加,达到动态扩展的效果 |
availablePermits() | 获取当前信号量可用的许可 |
小结
1.Semaphore是一个计数器,通过初始化的数值和其提供的方法来实现线程的控制。
2.Semaphore比较适合的场景是资源流量等控制。
3.Semaphore通过其提供的方法可以重复使用。
4.Semaphore提供的方法很多,通过灵活运用acquire(int permits)、release()等,可以在某些场景取代CountDownLatch或CyclicBarrier。
点赞收藏,富婆包养✋✋