可循环利用的过程,可以获得或者释放,当许可证的数量固定,获得许可证是类似”减法”的操作,减少许可证,释放类似于”加法”的操作,增加许可证。
使用场景
在实际生活中有很多的例子,比如停车场的车位数量有限,食堂的座位有限,这就需要控制入场的车或者人的数量,来维持秩序。
在计算机的世界里,Java并发靠线程来实现,线程之间的调度时间片切换靠CPU来管理,无节制的增加线程会加速消耗系统的资源,CPU飙升。
使用案例
使用Semaphore简单模拟停车场固定车位数量停车场景。
package juc.semaphore;import java.util.ArrayList;import java.util.List;import java.util.concurrent.Semaphore;import java.util.concurrent.TimeUnit;/*** Semaphore停车场景模拟* <p>* 简介:* 通过Semaphore来模拟停车场车辆停车,为防止循环一直无限循环下去,设置cycles循环次数,当达到次数后退出模拟。* <p>* 参数介绍:* cycles 循环总次数,curCycle 当前循环,permits 许可证即车位数量* <p>* 方法介绍:* checkCar()开启线程检验当前已获得停车位的汽车数量,并输出到控制台。* CheckExit()开启线程检验当前循环周期次数(即许可证为0的情况次数)并输出到控制台。* <p>* 补充:* 创建Thread模拟新到来的汽车,Car类模拟汽车的停车park()(获得许可证,parkCarList数量加一),离开leave()(释放许可证,parkCarList数量减一)* 通过time()方法来模拟过程启动,停车等延迟,防止启动就出现OOM的情况** @author starsray* @date 2021/12/16*/public class ParkingSpace {/*** 循环次数*/private final int cycles = 5;/*** 当前循环*/private int curCycle;/*** 许可证*/private final int permits = 5;/*** 获得停车位的汽车列表*/private static final List<Car> parkCarList = new ArrayList<>();/*** 信号量*/private final Semaphore semaphore = new Semaphore(permits);public static void main(String[] args) {ParkingSpace parkingSpace = new ParkingSpace();parkingSpace.test();}private void test() {checkCar();CheckExit();while (true) {time(1, 1);Thread thread = new Thread(new Car());thread.start();}}private void checkCar() {Thread thread = new Thread(() -> {while (true) {try {TimeUnit.SECONDS.sleep(2);if (parkCarList.size() > 0) {System.out.println("current car list : " + parkCarList.size());}} catch (InterruptedException e) {e.printStackTrace();}}});thread.setDaemon(true);thread.start();}private void CheckExit() {Thread thread = new Thread(() -> {System.out.println("running...");while (true) {try {TimeUnit.SECONDS.sleep(5);int permits = semaphore.availablePermits();if (permits == 0) {curCycle++;}System.out.printf("when destroy left %s times\n", cycles - curCycle);if (curCycle == cycles) {System.out.println("Game Over!");System.exit(0);}} catch (InterruptedException e) {e.printStackTrace();}}});thread.setDaemon(true);thread.start();}class Car implements Runnable {@Overridepublic void run() {work();}private void work() {park();leave();}private void leave() {semaphore.release(1);parkCarList.remove(this);}private void park() {try {time(1, 1);semaphore.acquire(1);parkCarList.add(this);time(10, 10);} catch (InterruptedException e) {semaphore.release(1);e.printStackTrace();}}}private void time(int init, int timeout) {int time = (int) (init + Math.random() * (timeout));try {TimeUnit.SECONDS.sleep(time);} catch (InterruptedException e) {e.printStackTrace();}}}
