原理
Semaphore(计数信号量)用来控制同时访问特定资源的线程数量,通过协调多线程,确保资源被合理使用。正常的锁在任何时刻都是只允许一个任务访问一项资源,而Semaphore允许多个任务同时访问一项资源。某些程度上和线程池有些相似,可用的数量固定,线程使用完后,剩下的进行排队,当有线程使用完毕后,放回线程池,然后再分配给排队的任务进行使用。
作用
Semaphore用来限制线程并发数量,用于限流,对访问的资源进行数量限制,比如:视频账号只允许最多两端同时在线,手机和电脑可以同时在线,若是想在平板上登录,手机和电脑中必须有一端退出登录才行;疫苗接种房间最多同时接种10人,接种者进入房间前发放许可证,只有手持许可证才能进入房间接种,10张许可证发放完后,剩下的人排队等着,接种完后收回许可证发放给后面排队的人进行接种。
public Semaphore(int permits) public Semaphore(int permits, boolean fair) acquire()acquire(int permits)acquireUninterruptibly() acquireUninterruptibly(int permits)tryAcquire()tryAcquire(long timeout, TimeUnit unit)release() release(int permits) availablePermits() drainPermits()reducePermits(int reduction) getQueueLength() hasQueuedThreads() // 5张许可证
final Semaphore semaphore = new Semaphore(5);
// 使用线程池
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
int finalI = i;
Runnable runnable = () -> {
try {
// 获取许可
semaphore.acquire();
System.out.println("第" + finalI + "位开始接种");
// 睡眠
Thread.sleep(new Random().nextInt(10000));
System.out.println("第" + finalI + "位接种完毕");
// 释放许可
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
executorService.execute(runnable);
}
executorService.shutdown();
结果:
第0位开始接种
第1位开始接种
第2位开始接种
第3位开始接种
第4位开始接种
第3位接种完毕
第8位开始接种
第4位接种完毕
第5位开始接种
第1位接种完毕
第9位开始接种
第8位接种完毕
第7位开始接种
第5位接种完毕
第6位开始接种
第7位接种完毕
第0位接种完毕
第2位接种完毕
第6位接种完毕
第9位接种完毕
观察结果发现,0、1,2、3、4满5位后就没有开始接种的,只有第3位接种完毕后,空出一个位置,这个位置给了第8位,第4位接种完毕后空位给了第5位,第1位接种完毕后空出的位置给了第9位,总而言之,就是空出一位顶上一位,直到所有人接种完毕。