Semaphore(信号量),是一种计数器,用来保护一个或者多个共享资源的访问,如果线程要访问一个资源就必须先获得信号量,如果信号量内部计数器大于 0 ,信号量减 1,然后允许共享这个资源,否则,如果信号量的计数器等于 0,信号量会把线程置入休眠,直至计数器大于 0,当信号量使用完时,必须释放
构造方法
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
- permits 初始线程数,也就是最大访问线程数
- fair 当设置 false 时,创建的信号量为非公平模式,当设置为 true 时,信号量时公平模式
主要的方法
- void acquire() :从信号量获取一个许可,如果无可用许可当前线程将一直阻塞等待,
- void acquire(int permits) :获取指定数目的许可,如果无可用许可当前线程也将会一直阻塞等待
- boolean tryAcquire():从信号量尝试获取一个许可,如果无可用许可,直接返回false,不会阻塞
- boolean tryAcquire(int permits): 尝试获取指定数目的许可,如果无可用许可直接返回false
- boolean tryAcquire(int permits, long timeout, TimeUnit unit): 在指定的时间内尝试从信号量中获取许可,如果在指定的时间内获取成功,返回true,否则返回false
- void release(): 释放一个许可,别忘了在finally中使用,注意:多次调用该方法,会使信号量的许可数增加,达到动态扩展的效果,如:初始permits为1, 调用了两次release,最大许可会改变为2
- int availablePermits(): 获取当前信号量可用的许可
Semophore 模拟简单限流场景
public class SemaphoreDemo{
public static void main(String[] args) {
// 令牌数最大 5 个,没有令牌无法访问
Semaphore semaphore = new Semaphore(5);
// 模拟 50 个线程,每次最多 5 个线程访问
for (int i = 0; i < 50; i++) {
new Thread(new Car(semaphore,i)).start();
}
}
static class Car implements Runnable{
Semaphore semaphore;
int num;
public Car(Semaphore semaphore,int num){
this.semaphore = semaphore;
this.num = num;
}
@Override
public void run() {
try {
semaphore.acquire(); // 获得令牌,如果没有获取到令牌 阻塞
System.out.println("第"+num+"个线程占用了一个令牌");
// 模拟访问时间
Thread.sleep(3000);
System.out.println("第"+num+"个线程释放了一个令牌");
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
semaphore.release(); // 释放令牌
}
}
}
}
结果
第1个线程占用了一个令牌
第3个线程占用了一个令牌
第5个线程占用了一个令牌
第7个线程占用了一个令牌
第9个线程占用了一个令牌
第3个线程释放了一个令牌
第1个线程释放了一个令牌
第11个线程占用了一个令牌
第13个线程占用了一个令牌
第5个线程释放了一个令牌
第15个线程占用了一个令牌
第9个线程释放了一个令牌
第7个线程释放了一个令牌
第17个线程占用了一个令牌
第19个线程占用了一个令牌
第11个线程释放了一个令牌
......
网友评论