多线程并发之Semaphore(信号量)使用详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/J080624/article/details/85625350

专题相关文章:

从内存可见性看Volatile、原子变量和CAS算法
多线程并发之CountDownLatch(闭锁)使用详解
多线程并发之显示锁Lock与其通信方式Condition源码解读
多线程并发之读写锁(ReentranReadWriteLock&ReadWriteLock)使用详解
多线程并发之线程池Executor与Fork/Join框架
多线程并发之JUC 中的 Atomic 原子类总结
多线程并发之volatile的底层实现原理
多线程并发之Semaphore(信号量)使用详解

【1】Semaphore简介

① 是什么

信号量(Semaphore),又被称为信号灯,在多线程环境下用于协调各个线程, 以保证它们能够正确、合理的使用公共资源。信号量维护了一个许可集,我们在初始化Semaphore时需要为这个许可集传入一个数量值,该数量值代表同一时间能访问共享资源的线程数量。线程可以通过acquire()方法获取到一个许可,然后对共享资源进行操作,注意如果许可集已分配完了,那么线程将进入等待状态,直到其他线程释放许可才有机会再获取许可,线程释放一个许可通过release()方法完成,"许可"将被归还给Semaphore。

② 类结构

如下图所示,与ReentrantLock一样基于AQS的子类Sync并有公平和非公平模式。
在这里插入图片描述

③ Javadoc

Semaphore不使用实际的"许可"对象,只保留可用数量的计数,并相应地执行操作。信号量通常用来限制访问某些(物理或逻辑)资源线程的数量。

例如,下面是一个使用信号量控制对项目池访问的类:

public class SemaphorePool {
   private static final int MAX_AVAILABLE = 100;
   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);

   public Object getItem() throws InterruptedException {
     available.acquire();
     return getNextAvailableItem();
   }

   public void putItem(Object x) {
     if (markAsUnused(x))
       available.release();
   }

   // Not a particularly efficient data structure; just for demo
   protected Object[] items = ...; //whatever kinds of items being managed
   protected boolean[] used = new boolean[MAX_AVAILABLE];

   protected synchronized Object getNextAvailableItem() {
     for (int i = 0; i < MAX_AVAILABLE; ++i) {
       if (!used[i]) {
          used[i] = true;
          return items[i];
       }
     }
     return null; // not reached
   }

   protected synchronized boolean markAsUnused(Object item) {
     for (int i = 0; i < MAX_AVAILABLE; ++i) {
       if (item == items[i]) {
          if (used[i]) {
            used[i] = false;
            return true;
          } else
            return false;
       }
     }
     return false;
   }
 }

在获取一个item前,每个线程都要从Semaphore处获取一个许可,保证有个可用的item供线程使用。当线程使用完item,则将item归还到pool中并归还许可给Semaphore供其他线程使用。注意,当调用acquire方法时,不会保持同步锁,因为这样会阻止item返回池。信号量封装了限制对池的访问所需的同步,与维护池本身一致性所需的任何同步分开。

一个初始化为1的信号量,最多只能有一个可用的许可证,它可以作为互斥锁。这通常被称为二进制信号量,因为它只有两种状态:一个允许可用,或者零个允许可用。当以这种方式使用时,不同于其他java.util.concurrent.locks.Lock的实现,二进制信号量具有某种属性–“锁”可以由所有者以外的线程释放(因为信号量没有所有权的概念)。这在某些特定的上下文中很有用,例如死锁恢复。

此类的构造函数可以选择性地接受一个“公平”参数。当参数为false时,Semaphore不保证线程获取许可的顺序。

未完待续。。

猜你喜欢

转载自blog.csdn.net/J080624/article/details/85625350