信号量(Semaphore)。有时被称为信号灯。是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们可以正确、合理的使用公共资源。
一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要。在许可可用前会堵塞每个 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