我的理解~~
【信號量】:
- 用於控制對某資源訪問的同一時間的並發量。
【如何獲取】:
- 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/