可循环利用的过程,可以获得或者释放,当许可证的数量固定,获得许可证是类似”减法”的操作,减少许可证,释放类似于”加法”的操作,增加许可证。
使用场景
在实际生活中有很多的例子,比如停车场的车位数量有限,食堂的座位有限,这就需要控制入场的车或者人的数量,来维持秩序。
在计算机的世界里,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 {
@Override
public 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();
}
}
}