Semaphore信号量是Java一个并发工具类

概述

信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。

计数信号量用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量。信号量还可以用来实现某种资源池,或者对容器施加边界。

原理

Semaphore的实现原理与阻塞队列相似:
Semaphore管理着一组许可(permit),许可的初始数量可以通过构造函数设定。操作时首先要获取到许可,才能进行操作,操作完成后需要释放许可。如果没有获取许可,则阻塞直到有许可被释放。如果初始化了一个许可为1的Semaphore,那么就相当于一个不可重入的互斥锁(Mutex)。

image.png

形象点的解释就是一个厕所里只有三个坑,但是现在有五个人要方便,所以只能进去三个人其他两个人只能在外面排队等待(阻塞)。等到有一个人解决完出来了,就又可以进去一个人了。

方法

下面是部分方法:

  1. public class Semaphore implements java.io.Serializable {
  2. //获取许可,如果许可已经满了,则阻塞
  3. public void acquire() throws InterruptedException;
  4. //获取指定数量的许可
  5. public void acquire(int permits) throws InterruptedException;
  6. //释放许可
  7. public void release();
  8. //获取当前可用许可数量
  9. public int availablePermits();
  10. //仅在调用时可用时,才从此信号量获取许可。
  11. public boolean tryAcquire();
  12. //如果在给定的等待时间内可用,并且当前线程尚未中断,则从此信号量获取许可。
  13. public boolean tryAcquire(long timeout, TimeUnit unit)
  14. throws InterruptedException;
  15. //仅在调用时所有可用的条件下,从此信号量获取给定数量的许可。
  16. public boolean tryAcquire(int permits);
  17. //如果所有信号在给定的等待时间内可用,并且当前线程未中断,则从该信号量获取给定数量的许可。
  18. public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
  19. throws InterruptedException
  20. }

实例

下面是一个简单的信号量使用实例:

  1. public void semaphore(){
  2. //线程池
  3. ExecutorService executorService = Executors.newCachedThreadPool();
  4. //信号量,最多5个线程同时访问
  5. final Semaphore semaphore = new Semaphore(5);
  6. //模拟10个客户端访问
  7. for(int i = 0; i < 10; i++){
  8. Runnable runnable = new Runnable() {
  9. @Override
  10. public void run() {
  11. try{
  12. //请求许可
  13. semaphore.acquire();
  14. Thread.sleep(5000);
  15. //访问完后,释放
  16. semaphore.release();
  17. System.out.println(semaphore.availablePermits());
  18. }catch (InterruptedException e){
  19. e.printStackTrace();
  20. }
  21. }
  22. };
  23. //执行任务
  24. executorService.execute(runnable);
  25. }
  26. //关闭线程池
  27. executorService.shutdown();
  28. }