Semaphore中管理着一组虚拟的访问许可,可通过构造函数来指定【new Semaphore(N);】,执行操作前首先获得许可【semaphore.acquire();】,使用后释放许可【semaphore.release();】。如果没有获得许可,那么这个acquire函数会阻塞,直到有许可释放,这个地方是有死锁的风险的,所以释放许可尽量放在finally中。
下面模拟卫生间上厕所的程序。
假设我们要实现一套自动控制厕所门入口门禁的系统(简单起见,大小便池统一计算),厕所有10个坑,有20个人要上厕所,人满了就不能放人进来了,在外面等着,这个只能控制进入人数,并不能控制顺序。
代码:
public class Main {
private static final int N = 10;
private static Random sRandom = new Random();
public static final void main(String[] args) {
testSemaphore();
}
private static void testSemaphore() {
final Semaphore semaphore = new Semaphore(N);
for (int i=0; i<N * 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("用户" + Thread.currentThread().getId() + "排队上厕所");
try {
semaphore.acquire();
System.out.println("用户" + Thread.currentThread().getId() + "进入厕所");
// 模拟上厕所耗时
int duration = sRandom.nextInt(3000);
Thread.sleep(duration);
System.out.println("用户" + Thread.currentThread().getId() + "上完厕所,用时:" + duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("用户" + Thread.currentThread().getId() + "离开厕所");
semaphore.release();
}
}
}).start();
}
}
}
输出:
用户11排队上厕所
用户16排队上厕所
用户18排队上厕所
用户12排队上厕所
用户19排队上厕所
用户13排队上厕所
用户14排队上厕所
用户15排队上厕所
用户10排队上厕所
用户22排队上厕所
用户15进入厕所
用户14进入厕所
用户24排队上厕所
用户21排队上厕所
用户13进入厕所
用户20排队上厕所
用户19进入厕所
用户12进入厕所
用户18进入厕所
用户16进入厕所
用户11进入厕所
用户17排队上厕所
用户29排队上厕所
用户28排队上厕所
用户27排队上厕所
用户26排队上厕所
用户25排队上厕所
用户22进入厕所
用户23排队上厕所
用户10进入厕所
用户13上完厕所,用时:113
用户13离开厕所
用户24进入厕所
用户18上完厕所,用时:167
用户18离开厕所
用户21进入厕所
用户16上完厕所,用时:776
用户16离开厕所
用户20进入厕所
用户24上完厕所,用时:1030
用户24离开厕所
用户17进入厕所
用户10上完厕所,用时:1186
用户10离开厕所
用户29进入厕所
用户29上完厕所,用时:156
用户29离开厕所
用户28进入厕所
用户15上完厕所,用时:1496
用户15离开厕所
用户27进入厕所
用户28上完厕所,用时:306
用户28离开厕所
用户26进入厕所
用户12上完厕所,用时:1656
用户12离开厕所
用户25进入厕所
用户20上完厕所,用时:909
用户20离开厕所
用户23进入厕所
用户11上完厕所,用时:1697
用户11离开厕所
用户26上完厕所,用时:268
用户26离开厕所
用户19上完厕所,用时:2315
用户19离开厕所
用户21上完厕所,用时:2145
用户21离开厕所
用户22上完厕所,用时:2548
用户22离开厕所
用户27上完厕所,用时:1069
用户27离开厕所
用户14上完厕所,用时:2679
用户14离开厕所
用户25上完厕所,用时:1499
用户25离开厕所
用户17上完厕所,用时:2961
用户17离开厕所
用户23上完厕所,用时:2995
用户23离开厕所
网友评论