【Java并发编程】Semaphore

什么是Semaphore?

Semaphore(信号量)是用于控制 同时访问特定资源的线程的数量,它通过协调各个线程,保证合理的使用公共资源。
线程可以通过acquire()方法来获取信号量的许可,当信号量中没有可用的许可的时候,线程阻塞,直到有可用的许可为止。线程可以通过release()方法释放它持有的信号量的许可。

怎么用Semaphore?

代码如下:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
   //模拟的线程数量
   private final static int threadCount = 20;
   public static void main(String[] args) throws Exception {
       //线程池
       ExecutorService exec = Executors.newCachedThreadPool();
   	   //同时允许3个线程执行
       final Semaphore semaphore = new Semaphore(3);
       
       //通过lambda表达式创建线程,同时添加进入线程池中
       for (int i = 0; i < threadCount; i++) {
           final int threadNum = i;
           exec.execute(() -> {
               try {
                   semaphore.acquire(); // 获取一个许可
                   test(threadNum);
                   semaphore.release(); // 释放一个许可
               } catch (Exception e) {
                   e.printStackTrace();
               }
           });
       }
       exec.shutdown();
   }
   private static void test(int threadNum) throws Exception {
       System.out.println(threadNum);
       Thread.sleep(1000);
   }
}

如代码所示,在new Semaphore(3),向里面传递了一个整数3,表示同时允许3个线程运行。当运行到semaphore.acquire()时,会去请求一个许可,默认不传参的情况下是一个许可:
在这里插入图片描述
当然你可以向里面传入一个正整数,比如3,那么就会向外发放3个许可。
在这里插入图片描述

需要注意的三点是:

  1. permis必须是正整数
  2. permis必须小于new Semaphore()时传入的数字。
    如果大于,程序则会因为没有将许可发放完毕而一直处于等待转态。这是因为semaphone在发放许可时,必须等到指定的许可数量发放完毕,才会让得到许可的线程执行。
    例如:在new Semaphore()时传值3,而acquire()时传值4,那么接下来semaphore会放行3个线程,等到了发放许可的时候,会将4个许可中的3个发放给被放行的3个线程,而第4个许可却迟迟发不出去了,这时便会陷入僵局之中,外面的线程想进去,里面的线程出不去。
  3. 向acquire()和release()中传递的值最好相等,否则可能会出错
    在这里插入图片描述
    使用acquire()方法的线程在没有得到许可的情况下,会处于阻塞状态,直到获取许可为止。
    与此不同的是tryAcquire()方法,使用该方法的线程会去尝试获取许可,当没有获取许可时,线程会被抛弃。
    在这里插入图片描述
    不过可以设置等待时间,在等待时间内获取到许可,线程就不会被抛弃了。

参考

java并发核心一Semaphore 的使用思路
JUC回顾之-Semaphore底层实现和原理

猜你喜欢

转载自blog.csdn.net/HuaLingPiaoXue/article/details/89260119
今日推荐