浅谈 java 信号量 Semaphore

时间:2022-06-14 15:14:02
  • 简介
           Semaphore主要是在多线程中可以轻松控制信号量,针对某个资源可被并发访问的个数。
 acquire()方法可以或得一个访问的许可,release()方法释放一个许可。
提供同步机制,控制同时访问的个数。

  • 应用场景举例     
              模拟银行窗口处理业务情景
同时有5个窗口处理业务,有10个顾客等待

 
  • 代码示例
            
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * User: ww.wang
 * Date: 2016/8/26
 * Time: 17:12
 */
public class TestSemaphore {
    public static void main(String[] args){
        //构造线程池
        ExecutorService  executorService = new ThreadPoolExecutor(5,10,3000, TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>(100));
        //构造信号量 5
        Semaphore  semaphore = new Semaphore(5);
        //模拟 10个顾客等待银行 5个窗口办理业务
        for (int i=1;i<=10;i++){
            final  int customID = i;
            Runnable runnable = new Runnable(){
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        System.out.println("客户"+customID+"正在办理业务");
                        //业务办理时间为随机几秒钟
                        long time = (long)(Math.random()*10000);
                        Thread.sleep(time);
                        System.out.println("客户"+customID+"办理业务花费了"+time+"毫秒");
                        semaphore.release();
                        System.out.println("客户"+customID+"办理业务结束");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            executorService.submit(runnable);
        }
        //关闭线程池
        executorService.shutdown();
    }
}

  • 运行结果
      
"C:\Program Files\Java\jdk1.8.0_66\bin\java" -Didea.launcher.port=7535 "-Didea.launcher.bin.path=C:\Program Files (x86)\JetBrains\IntelliJ IDEA 15.0.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_66\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_66\jre\lib\rt.jar;D:\work\eb\ebredesign\code\gitprojects\leo\out\production\leo;C:\Program Files (x86)\JetBrains\IntelliJ IDEA 15.0.6\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain TestSemaphore
客户1正在办理业务
客户2正在办理业务
客户3正在办理业务
客户4正在办理业务
客户5正在办理业务
客户1办理业务花费了936毫秒
客户1办理业务结束
客户6正在办理业务
客户2办理业务花费了2556毫秒
客户2办理业务结束
客户7正在办理业务
客户6办理业务花费了2504毫秒
客户6办理业务结束
客户8正在办理业务
客户7办理业务花费了2057毫秒
客户7办理业务结束
客户9正在办理业务
客户5办理业务花费了4982毫秒
客户5办理业务结束
客户10正在办理业务
客户4办理业务花费了7183毫秒
客户4办理业务结束
客户9办理业务花费了3444毫秒
客户9办理业务结束
客户3办理业务花费了9197毫秒
客户3办理业务结束
客户10办理业务花费了4501毫秒
客户10办理业务结束
客户8办理业务花费了6619毫秒
客户8办理业务结束

Process finished with exit code 0
  • 总结
       以上代码测试可以看出,五个窗口同时工作,10个顾客等等待,然而通知处理业务的客户一直是5个
      客户1  办理结束
      客户6开始办理
      一个释放许可一个获取。
 
拓展:如果再加个vip窗口,在加5个vip客户   ,vip窗口只处理vip客户,普通窗口 如果有vip就优先处理vip  这个业务又如何实现呢