1.定义
Semaphore又称“计数信号量”,主要用来控制同时访问某个特定资源的线程数量,通过构造方法传入某个资源需要设定的最大访问数量。 其内部抽象出“虚拟许可”的概念,许可的初始数量等于通过构造函数来指定。每个线程在执行操作时需要首先获取许可,并在使用完毕后释放许可,以供其他线程使用。如果未获取到许可,那么获取操作将会被阻塞直到有可用的许可。
* A counting semaphore. Conceptually, a semaphore maintains a set of
* permits. Each {@link #acquire} blocks if necessary until a permit is
* available, and then takes it. Each {@link #release} adds a permit,
* potentially releasing a blocking acquirer.这段话是从类注释搬运过来的,大概意思就是semaphore维护了一个许可集合,每个acquire获取操作都会被block知道有一个证书时可用的,每个release操作都会释放一个证书,并且可能释放一个阻塞的获取操作线程。
2. 使用用例
下面通过一个小例子学习一下Semaphore的简单使用:
package com.bonc.omc.lll.thread.juc;
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
public static void main(String[] args) {
final int maxPermitCount = 2;
final Semaphore semaphore = new Semaphore(2);
System.out.println("本银行目前开放两个窗口,开始办理业务");
for (int i=0; i<8; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
"进入,当前已有" + (maxPermitCount-semaphore.availablePermits()) + "个顾客正在办理业务");
try {
Thread.sleep((long)(Math.random()*10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
"正在办理业务....");
semaphore.release();
//下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
System.out.println(Thread.currentThread().getName() +
"办理完业务,当前有" + (maxPermitCount-semaphore.availablePermits()) + "个顾客正在办理业务");
}
});
thread.setName("顾客-"+i);
thread.start();
}
}
}
输出结果:
3.源码分析
通过上面的简单示例,我们已经简单掌握了Semaphore的基本使用,而我们的目的显然不是仅仅写个Demo简单学习下如何使用,源码学习才是我们的终极目标。go....
先看下Semaphore类中都包含哪些成员变量和方法:
3.1构造方法
Semaphore提供两种进行初始化的构造方法,均可通过入参决定permits的大小:
方法1:public Semaphore(int permits)
方法2:public Semaphore(int permits,boolean fair),其中相较方法1,可指定使用公平锁还是非公平锁。
- 当fair为false时,该类不保证线程获取许可的顺序。特别地,是允许阻塞的,也就是说,一个调用acquire的线程会进行插队,将自己放在等待线程队列的头部,这样就可以在一个正在等待的线程之前被分配一个许可证。
- 当fair为true时,信号量保证调用任何获取方法的线程会以其调用这些方法的顺序获得许可(先进先出)。请注意,FIFO顺序必然适用于这些方法中特定的内部执行点。因此,一个线程可能在另一个线程之前调用acquire,但在另一个线程之后到达排序点,从方法返回时也是如此。还要注意,非定时的tryAcquire方法不遵守公平性设置,但会接受任何可用的许可。
3.2 Sync类
从上面的关于类成员的截图中可以看到,Semaphore类中包含一个sync变量,它的类型是Sync。
Sync是一个抽象静态类,继承于AbstractQueuedSynchronizer(抽象队列同步器,详细内容不在本篇进行扩展)
未完待续,,,,