Semaphore
翻译:Semaphore 信号量;信号灯;信号
模拟6个车抢三个车位
public class Test2 {
/**
* 信号灯
*/
public static void main(String[] args) {
//模拟资源类,有三个停车位
Semaphore semaphore = new Semaphore(3);
for (int i=1;i<=6;i++){
new Thread(()->{//模拟6个车去抢三个车位
try {
semaphore.acquire();//acquire得到
System.out.println(Thread.currentThread().getName()+"抢到了车位!");
TimeUnit.SECONDS.sleep(4);
System.out.println(Thread.currentThread().getName()+"离开了车位!");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();//release释放
}
}).start();
}
}
}
- Semaphore是计数信号量。Semaphore管理一系列许可证。每个acquire方法阻塞,直到有一个许可证可以获得然后拿走一个许可证;每个release方法增加一个许可证,这可能会释放一个阻塞的acquire方法。然而,其实并没有实际的许可证这个对象,Semaphore只是维持了一个可获得许可证的数量。
源码解析
Semaphore有两种模式,公平模式和非公平模式。公平模式就是调用acquire获取许可证的顺序,遵循FIFO;而非公平模式是抢占式的,也就是有可能一个新的获取线程恰好在一个许可证释放时得到了这个许可证,而前面还有等待的线程。
- 构造方法
Semaphore有两个构造方法,如下:
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
- 从上面可以看到两个构造方法,都必须提供许可的数量,第二个构造方法可以指定是公平模式还是非公平模式,默认非公平模式。
Semaphore内部基于AQS的共享模式,所以实现都委托给了Sync类。
这里就看一下NonfairSync的构造方法:
NonfairSync(int permits) {
super(permits);
}
可以看到直接调用了父类的构造方法,Sync的构造方法如下:
Sync(int permits) {
setState(permits);
}
可以看到调用了setState方法,也就是说AQS中的资源就是许可证的数量。
总结
Semaphore是信号量,用于管理一组资源。其内部是基于AQS的共享模式,AQS的状态表示许可证的数量,在许可证数量不够时,线程将会被挂起;而一旦有一个线程释放一个资源,那么就有可能重新唤醒等待队列中的线程继续执行。