JUC之Semaphore

流量控制 Semaphore

Semaphore是一个计数的信号量。初始化时分配一个配额permits。在访问前需要用acquire()方法申请一个配额,访问结束后调用release()释放配置。申请配额时如果配额不足将会阻塞。

使用例子

例子:有2个足球,4个人射门练习。每个人射门后都要把球拿回来,后面的人才能射球。这里足球就是配额。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Player implements  Runnable {

private final Semaphore semaphore;

public Player(Semaphore semaphore){
this.semaphore=semaphore;
}
public void run() {
try {
semaphore.acquire();
//踢完还剩余的球
System.out.println("踢球。。。。"+semaphore.availablePermits());
int millis = new Random().nextInt(4)+1;
Thread.sleep(millis*1000);
System.out.println(String.format("捡球花时间%d秒",millis));
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
}
}
}


public static void main(String[] args){

Semaphore semaphore = new Semaphore(2);

for(int i=0;i<4;i++){
new Thread(new Player(semaphore)).start();
}

try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}

}

结果

1
2
3
4
5
6
7
8
踢球。。。。1
踢球。。。。0
捡球花时间4秒
捡球花时间4秒
踢球。。。。0
踢球。。。。0
捡球花时间1秒
捡球花时间2秒

常用API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void acquire() 
从该信号量获取许可证,阻止直到可用,或线程为 interrupted 。
void acquire(int permits)
从该信号量获取给定数量的许可证,阻止直到所有可用,否则线程为 interrupted 。
void acquireUninterruptibly()
从这个信号灯获取许可证,阻止一个可用的。
void acquireUninterruptibly(int permits)
从该信号量获取给定数量的许可证,阻止直到所有可用。
int availablePermits()
返回此信号量中当前可用的许可数。
int drainPermits()
获取并返回所有可立即获得的许可证。
protected Collection<Thread> getQueuedThreads()
返回一个包含可能正在等待获取的线程的集合。
int getQueueLength()
返回等待获取的线程数的估计。
boolean hasQueuedThreads()
查询任何线程是否等待获取。
boolean isFair()
如果此信号量的公平设置为真,则返回 true
protected void reducePermits(int reduction)
缩小可用许可证的数量。
void release()
释放许可证,将其返回到信号量。
void release(int permits)
释放给定数量的许可证,将其返回到信号量。
String toString()
返回一个标识此信号量的字符串及其状态。
boolean tryAcquire()
从这个信号量获得许可证,只有在调用时可以使用该许可证。
boolean tryAcquire(int permits)
从这个信号量获取给定数量的许可证,只有在调用时全部可用。
boolean tryAcquire(int permits, long timeout, TimeUnit unit)
从该信号量获取给定数量的许可证,如果在给定的等待时间内全部可用,并且当前线程尚未 interrupted 。
boolean tryAcquire(long timeout, TimeUnit unit)
如果在给定的等待时间内可用,并且当前线程尚未 到达 interrupted,则从该信号量获取许可。

总结

  1. Semaphore内部是由共享锁实现的。
  2. Semaphore支持公平锁和非公平锁。默认是非公平锁。可以通过构造函数设置。