1. 什么是Semaphore
Semaphore(信号量)是用来控制同时访问特定资源的线程数量, 它通过协调各个线程, 以保证合理的使用公共资源。
比喻解释:
我们可以把Semaphore比作是控制流量的红绿灯。
eg:
XX马路要限制流量, 只允许同时有一百辆车在这条路上行使, 其他的都必须在路口等待。
如果前一百辆车看到绿灯, 可以开进这条马路;
后面的车会看到红灯, 不能驶入XX马路。
但是如果前一百辆中有五辆车已经离开了XX马路, 那么后面就允许有5辆车驶入马路。
这个例子里说的车就是线程
驶入马路就表示线程在执行
离开马路就表示线程执行完成
看见红灯就表示线程被阻塞, 不能执行
2. 实际例子
Semaphore机制是提供给线程抢占式获取许可,所以他可以实现公平或者非公平,类似于ReentrantLock。
说了这么多我们来个实际的例子看一看。
eg:
我们去停车场停车,停车场总共只有5个车位,
但是现在有8辆汽车来停车,剩下的3辆汽车要么等其他汽车开走后进行停车。
代码:
public class SemaphoreTest { public static void main(String[] args) throws InterruptedException { // 初始化五个车位 Semaphore semaphore = new Semaphore(5); // 等所有车子 final CountDownLatch latch = new CountDownLatch(8); for (int i = 0; i < 8; i++) { int finalI = i; if (i == 5) { Thread.sleep(1000); new Thread(() -> { stopCarNotWait(semaphore, finalI); latch.countDown(); }).start(); continue; } new Thread(() -> { stopCarWait(semaphore, finalI); latch.countDown(); }).start(); } latch.await(); log("总共还剩:" + semaphore.availablePermits() + "个车位"); } private static void stopCarWait(Semaphore semaphore, int finalI) { String format = String.format("车牌号%d", finalI); try { semaphore.acquire(1); log(format + "找到车位了,去停车了"); Thread.sleep(10000); } catch (Exception e) { e.printStackTrace(); } finally { semaphore.release(1); log(format + "开走了"); } } private static void stopCarNotWait(Semaphore semaphore, int finalI) { String format = String.format("车牌号%d", finalI); try { if (semaphore.tryAcquire()) { log(format + "找到车位了,去停车了"); Thread.sleep(10000); log(format + "开走了"); semaphore.release(); } else { log(format + "没有停车位了,不在这里等了去其他地方停车去了"); } } catch (Exception e) { e.printStackTrace(); } } public static void log(String content) { // 格式化 DateTimeFormatter fmTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 当前时间 LocalDateTime now = LocalDateTime.now(); System.out.println(now.format(fmTime) + " "+content); } }
运行结果:
2021-04-20 18:54:57 车牌号0找到车位了,去停车了
2021-04-20 18:54:57 车牌号3找到车位了,去停车了
2021-04-20 18:54:57 车牌号2找到车位了,去停车了
2021-04-20 18:54:57 车牌号1找到车位了,去停车了
2021-04-20 18:54:57 车牌号4找到车位了,去停车了
2021-04-20 18:54:58 车牌号5没有停车位了,不在这里等了去其他地方停车去了
2021-04-20 18:55:07 车牌号7找到车位了,去停车了
2021-04-20 18:55:07 车牌号6找到车位了,去停车了
2021-04-20 18:55:07 车牌号2开走了
2021-04-20 18:55:07 车牌号0开走了
2021-04-20 18:55:07 车牌号3开走了
2021-04-20 18:55:07 车牌号4开走了
2021-04-20 18:55:07 车牌号1开走了
2021-04-20 18:55:17 车牌号7开走了
2021-04-20 18:55:17 车牌号6开走了
2021-04-20 18:55:17 总共还剩:5个车位