Semaphore意为信号量,它用来限制某段时间内的最大并发资源数。例如数据库链接池,停车位等。下面经过停车位的栗子来讲明Semaphore的使用方式。java
import java.util.concurrent.Semaphore; public class SemaphoreDemo { private static Semaphore semaphore = new Semaphore(10); public static void main(String[] args) { for (int i = 1; i <= 50; i++) { new Thread(() -> { try { if (semaphore.availablePermits() == 0) { System.out.println("车位已满,须要等待..."); } semaphore.acquire(); System.out.println("有空余车位,驶进停车场"); // 模拟在停车场smoke or something Thread.sleep(3000); System.out.println("老婆喊我回家吃饭,驶出停车场"); semaphore.release(); } catch (InterruptedException e) { // ignored } }).start(); } } }
看一眼Semaphore的类结构,内部类继承了AQS,同时提供了公平和非公平策略。
咱们能够在构造函数中指定是公平仍是非公平,默认是非公平策略。数据库
public Semaphore(int permits, boolean fair) { sync = fair ? new FairSync(permits) : new NonfairSync(permits); }
public Semaphore(int permits) { sync = new NonfairSync(permits); }
再来看重要方法(以NonfairSync为例分析):
acquire()编程
public void acquire() throws InterruptedException { sync.acquireSharedInterruptibly(1); }
能够看到,调用了AQS的模板方法,acquireSharedInterruptibly里面会调用子类重写的tryAcquireShared,来看看相关逻辑:并发
public final void acquireSharedInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); // 调用子类方法尝试获取共享资源失败,则在队列中阻塞获取 if (tryAcquireShared(arg) < 0) doAcquireSharedInterruptibly(arg); }
protected int tryAcquireShared(int acquires) { return nonfairTryAcquireShared(acquires); }
final int nonfairTryAcquireShared(int acquires) { // CAS + 自璇 for (;;) { // 获取当前剩余资源数 int available = getState(); // 计算获取acquires个资源后,剩余资源数 int remaining = available - acquires; // 若是不够用或者够用而且CAS设置剩余数成功,则返回 // 不然循环重试CAS操做 if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } }
release()函数
public void release() { sync.releaseShared(1); }
一样,release调用了AQS的模板方法,releaseShared里面会调用子类重写的tryReleaseShared方法,来看看子类具体实现逻辑:ui
protected final boolean tryReleaseShared(int releases) { // CAS + 自璇 for (;;) { int current = getState(); int next = current + releases; if (next < current) // overflow throw new Error("Maximum permit count exceeded"); if (compareAndSetState(current, next)) return true; } }
代码逻辑也很简单,不作赘述。spa
FairSync公平式的获取,就是在tryAcquireShared时先判断队列中有无在等待的元素,有的话就返回-1,进入同步队列阻塞获取。相关代码以下:code
protected int tryAcquireShared(int acquires) { for (;;) { if (hasQueuedPredecessors()) return -1; int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; } }
参考资料:
《Java并发编程之美》继承