什么是Semaphore?
计数信号灯, Semaphore是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。
信号量维护一组许可证,使用acquire()去获取许可证,在未获取到许可证之前会一直阻塞,直到获取到许可证,最后使用release() 释放许可证供其它线程获取。
理解
相信大家都有排队就餐的经验,商场里一家非常火爆的餐厅,两百人来就餐,但是餐厅只有100个位子,前面一百人先进去就餐,后边100人就在外面取号排队,餐厅里面一桌客人走后,后面排队的100人才能进去一人,以此类推,出来一人进去一人,许可证可以理解为就是手中的号,号还没到你你就一直等待,当餐厅走了一个人,空出来一个空位置后,刚好号到你了,你就可以进去了(例子不严谨,只作为理解使用)。
Semaphore构造方法
1、
Semaphore(int permits)
使用给定
的许可数量和非公平性设置创建信号量。
2、Semaphore(int permits, boolean fair)
使用给定
的许可数量和给定
的公平性设置创建一个信号量。
permits
: 许可证-可用许可证的初始数量
fair
: 设置是公平竞争还是非公平竞争,默认是使用非公平竞争,非公平竞争效率会比公平竞争效率高,因为非公平竞争会减少线程上下文切换,通过减少线程的切换来提高效率,设置为true为公平竞争。
Semaphore方法
类型 | 方法 | 描述 |
---|---|---|
void | acquire() | 从这个信号量获取许可证,阻塞直到有一个可用,或者线程被中断 |
void | acquire(int permits) | 从这个信号量获取给定数量的许可证,阻塞直到所有许可证都可用,或者线程被中断 |
void | acquireUninterruptibly() | 从这个信号量获取许可证,阻塞直到有一个可用为止。 |
void | acquireUninterruptibly(int permits) | 从这个信号量获取给定数量的许可证,阻塞直到所有许可证都可用为止。 |
int | availablePermits() | 返回此信号量中当前可用的许可证数 |
int | drainPermits() | 获取并返回所有立即可用的许可证 |
protected Collection<Thread> | getQueuedThreads() | 返回包含可能正在等待获取的线程的集合 |
int | getQueueLength() | 返回等待获取的线程数的估计值 |
boolean | hasQueuedThreads() | 查询是否有线程正在等待获取 |
boolean | isFair() | 如果此信号量的公平性设置为true,则返回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) | 如果在给定的等待时间内所有许可证都可用,并且当前线程没有中断,则从该信号量获取给定数量的许可证 |
boolean | tryAcquire(long timeout, TimeUnit unit) | 如果在给定的等待时间内有一个可用,并且当前线程没有中断,则从该信号量获取许可 |
例子
package com.sy.thread.example;
import java.util.concurrent.Semaphore;
/**
* Description: thread
*
* @author songyu
*/
public class SemaphoreTest1 {
public static void main(String[] args) {
//定义一个有2个许可证的信号量
Semaphore semaphore = new Semaphore(2);
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
//获取信号量,获取不到将阻塞,直到获取到许可证
semaphore.acquire();
System.out.println("线程"+Thread.currentThread().getName() + "获取到许可证,开始执行。。。。。。");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//归还许可证
semaphore.release();
System.out.println("线程"+Thread.currentThread().getName() + "执行完毕,归还许可证");
}
}
}, String.valueOf(i)).start();
}
}
}
输出结果
线程0获取到许可证,开始执行。。。。。。
线程1获取到许可证,开始执行。。。。。。
线程0执行完毕,归还许可证
线程1执行完毕,归还许可证
线程3获取到许可证,开始执行。。。。。。
线程2获取到许可证,开始执行。。。。。。
线程2执行完毕,归还许可证
线程3执行完毕,归还许可证
线程4获取到许可证,开始执行。。。。。。
线程4执行完毕,归还许可证
通过执行结果可以看出,当2个许可证都被拿走后,其它来拿许可证的线程拿不到就一直被阻塞这,直到有的线程归还了许可证,阻塞中的线程抢到了许可证后才可以继续执行。
使用场景
限流