一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。拿到信号量的线程可以进入代码,否则就等待。通过acquire()和release()获取和释放访问许可。
package com.lala.shop;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreDemo
{
/**
* 这里演示了一个例子:十个人一起上厕所
* 如果一次只能一个人上厕所,则总共需要时间:1+2+3+4+5+6+7+8+9+10=55分钟
* 如果一次能10个人一起上厕所,则总共需要时间:10分钟
*/
static void demonstration(int num) throws Exception
{
String[] users = {"刘梅","夏东海","夏雪","刘星","夏雨","爷爷","姥姥","玛丽","胡一统","林宁"};
CountDownLatch cdl = new CountDownLatch(users.length);
Integer[] times = {1,2,3,4,5,6,7,8,9,10};
List<Integer> timeList = Arrays.asList(times);
Collections.shuffle(timeList);
Semaphore sph = new Semaphore(num);
ExecutorService runner = Executors.newCachedThreadPool();
Instant start = Instant.now();
for(int i=0; i<users.length; i++)
{
final int index = i;
runner.submit(() -> {
try
{
//拿到信号灯,准备上厕所
sph.acquire();
long time = timeList.get(index);
TimeUnit.SECONDS.sleep(time);
System.out.println(users[index] + "如厕完毕,共花费时间:" + time);
cdl.countDown();
//事情已经办完,释放信号灯
sph.release();
} catch (Exception e)
{
e.printStackTrace();
}
});
}
runner.shutdown();
cdl.await();
Instant end = Instant.now();
Duration speed = Duration.between(start, end);
long seconds = speed.getSeconds();//秒表示
System.out.println("全部上完厕所(一次只能有" + num + "人如厕),总共花了时间:" + seconds);
}
public static void main(String[] args) throws Exception
{
demonstration(5);
}
}
如果调用方式为:
demonstration(5);
则,输出为:
夏雪如厕完毕,共花费时间:1
夏雨如厕完毕,共花费时间:3
刘星如厕完毕,共花费时间:4
爷爷如厕完毕,共花费时间:6
夏东海如厕完毕,共花费时间:8
刘梅如厕完毕,共花费时间:9
胡一统如厕完毕,共花费时间:2
玛丽如厕完毕,共花费时间:7
林宁如厕完毕,共花费时间:5
姥姥如厕完毕,共花费时间:10
全部上完厕所(一次只能有5人如厕),总共花了时间:13
如果调用方式为:
demonstration(1);
则,输出为:
刘梅如厕完毕,共花费时间:10
夏东海如厕完毕,共花费时间:6
夏雪如厕完毕,共花费时间:3
刘星如厕完毕,共花费时间:9
夏雨如厕完毕,共花费时间:8
爷爷如厕完毕,共花费时间:4
姥姥如厕完毕,共花费时间:1
玛丽如厕完毕,共花费时间:5
胡一统如厕完毕,共花费时间:7
林宁如厕完毕,共花费时间:2
全部上完厕所(一次只能有1人如厕),总共花了时间:55
如果调用方式为
demonstration(10); 则输出为:
夏雨如厕完毕,共花费时间:1
夏东海如厕完毕,共花费时间:2
爷爷如厕完毕,共花费时间:3
刘星如厕完毕,共花费时间:4
刘梅如厕完毕,共花费时间:5
胡一统如厕完毕,共花费时间:6
林宁如厕完毕,共花费时间:7
姥姥如厕完毕,共花费时间:8
玛丽如厕完毕,共花费时间:9
夏雪如厕完毕,共花费时间:10
全部上完厕所(一次只能有10人如厕),总共花了时间:10