Semaphore,动态增减信号量
我的理解~~
【信号量】:
- 用于控制对某资源访问的同一时间的并发量。
【如何获取】:
- semaphore.tryAcquire(),尝试获取,不阻塞
- semaphore.acquire(),没信号量可用时,将进行阻塞等
【如何释放】:
- semaphore.release();
- 线程抛出各种异常,都别忘了在finally中释放信号量;
- 如果释放的比获取的信号量还多,例如获取了2个,释放了5次,那么当前信号量就动态的增加为5了,要注意。
【动态增加】:
- 多释放几次,就可以达到信号量动态增加的效果了
【动态减小】:
- 信号量本来有这个api的,不过是protected方法,所以我们需要显式继续Semaphore,并重新实现该api,见ResizeableSemaphore类中的reducePermits(int reduction);
- 举例如下:(该表格有个假设前提,不存在多余的release而产生出新的信号量,即release次数<=acquire次数)
当前信号量A (A=A1+A2) |
占用信号量A1 | 可用信号量A2 | 重新设置信号量B (B=B1+B2) |
当前可用的信号量B1 | 当前待释放的量B2 |
5 | 3 | 2 | 3 | 0 | 0 |
5 | 3 | 2 | 1 | 0 | -2 |
5 | 3 | 2 | 9 | 6 | 0 |
【动态减小—demo】:
import java.util.concurrent.Semaphore;
public class AdjustableSemaphore {
private final ResizeableSemaphore semaphore = new ResizeableSemaphore();
private int maxPermits = 0;
public AdjustableSemaphore(){
}
synchronized void setMaxPermits(int newMax){
if(newMax < 1){
throw new IllegalArgumentException("Semaphore size must be at least 1,"
+ " was " + newMax);
}
int delta = newMax - this.maxPermits;
if(delta == 0){
return ;
}else if(delta > 0){
this.semaphore.release(delta);
}else {
delta *= -1;
this.semaphore.reducePermits(delta);
}
this.maxPermits = newMax;
}
public int availablePermits(){
return this.semaphore.availablePermits();
}
public void release(){
this.semaphore.release();
}
public boolean tryAcquire(){
return this.semaphore.tryAcquire();
}
private static final class ResizeableSemaphore extends Semaphore {
ResizeableSemaphore(){
super(0);
}
@Override
protected void reducePermits(int reduction){
super.reducePermits(reduction);
}
}
}
【测试程序】:
AdjustableSemaphore semaphore = new AdjustableSemaphore();
System.out.println("==============5");
semaphore.setMaxPermits(5);
for(int i=0;i<20;i++){
semaphore.tryAcquire();
}
System.out.println(semaphore.availablePermits()); //5个信号量全被占用,所以当前可用的为0
System.out.println("==============2");
semaphore.setMaxPermits(2);
System.out.println(semaphore.availablePermits()); //将信号量显式设置为2,与上一步合并结果(2-5)=-3,表示目前有5个被占用,信号量只有2,所以还有3个欠着待释放
System.out.println("==============20");
semaphore.setMaxPermits(20);
System.out.println(semaphore.availablePermits());//将信号量显式设置为20,与上一步合并结果(20-2)+(-3)=15个,表示目前还有15个可用。
System.out.println("==============3");
semaphore.setMaxPermits(3);
System.out.println(semaphore.availablePermits());//同上,(3-20)+15=-2
System.out.println("==============1");
semaphore.setMaxPermits(1);
System.out.println(semaphore.availablePermits());//同上,(1-3)-2=-4
System.out.println("==============10");
semaphore.setMaxPermits(10);
System.out.println(semaphore.availablePermits());//同上,(10-1)-4=5
System.out.println("==============FINALLY");
for(int i=0;i<7;i++){
semaphore.release();
}
System.out.println(semaphore.availablePermits());//释放了7个,所以7+5=12,虽然显式设置了信号量为10,但因多release()了两次,所以无意之中隐式增大了信号量。
【输出结果】:
==============5
0
==============2
-3
==============20
15
==============3
-2
==============1
-4
==============10
5
==============FINALLY
10
这里可参考:http://blog.teamlazerbeez.com/2009/04/20/javas-semaphore-resizing/