Java中信號量 Semaphore

Semaphore 通常用於限制可以訪問某些資源(物理或邏輯的)的線程數目。自從5.0開始,jdk在java.util.concurrent包裏提供了Semaphore 的官方實現,因此大家不需要自己去實現Semaphore


下面的類使用信號量控制對內容池的訪問:

Java代碼  收藏代碼
  1. import java.util.concurrent.Semaphore;  
  2. class Pool {  
  3.     private static final int MAX_AVAILABLE = 100;  
  4.     private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);  
  5.     public Object getItem() throws InterruptedException {  
  6.         available.acquire(); // 從此信號量獲取一個許可,在提供一個許可前一直將線程阻塞,否則線程被中斷  
  7.         return getNextAvailableItem();  
  8.     }  
  9.     public void putItem(Object x) {  
  10.         if (markAsUnused(x))  
  11.             available.release(); // 釋放一個許可,將其返回給信號量  
  12.     }  
  13.     // 僅作示例參考,非真實數據  
  14.     protected Object[] items = null;  
  15.     protected boolean[] used = new boolean[MAX_AVAILABLE];  
  16.     protected synchronized Object getNextAvailableItem() {  
  17.         for (int i = 0; i < MAX_AVAILABLE; ++i) {  
  18.             if (!used[i]) {  
  19.                 used[i] = true;  
  20.                 return items[i];  
  21.             }  
  22.         }  
  23.         return null;  
  24.     }  
  25.     protected synchronized boolean markAsUnused(Object item) {  
  26.         for (int i = 0; i < MAX_AVAILABLE; ++i) {  
  27.             if (item == items[i]) {  
  28.                 if (used[i]) {  
  29.                     used[i] = false;  
  30.                     return true;  
  31.                 } else  
  32.                     return false;  
  33.             }  
  34.         }  
  35.         return false;  
  36.     }  
  37. }  

 

雖然JDK已經提供了相關實現,但是還是很有必要去熟悉如何使用Semaphore及其背後的原理。
做一個簡單的Semaphore實現

Java代碼  收藏代碼
  1. class SemaphoreTest {  
  2.     private boolean signal = false;  
  3.     public synchronized void take() {  
  4.         this.signal = true;  
  5.         this.notify();  
  6.     }  
  7.     public synchronized void release() throws InterruptedException {  
  8.         while (!this.signal)  
  9.             wait();  
  10.         this.signal = false;  
  11.     }  
  12. }  

 

使用這個semaphore可以避免錯失某些信號通知。用take方法來代替notify,release方法來代替wait。如果某線程在調用release等待之前調用take方法,那麼調用release方法的線程仍然知道take方法已經被某個線程調用過了,因爲該Semaphore內部保存了take方法發出的信號。而wait和notify方法就沒有這樣的功能。

 

可計數的Semaphore

Java代碼  收藏代碼
  1. class SemaphoreTest {  
  2.     private int signals = 0;  
  3.     public synchronized void take() {  
  4.         this.signals++;  
  5.         this.notify();  
  6.     }  
  7.     public synchronized void release() throws InterruptedException {  
  8.         while (this.signals == 0)  
  9.             wait();  
  10.         this.signals--;  
  11.     }  
  12. }  

 

Semaphore上限

Java代碼  收藏代碼
  1. class SemaphoreTest {  
  2.     private int signals = 0;  
  3.     private int bound = 0;  
  4.     public SemaphoreTest(int upperBound) {  
  5.         this.bound = upperBound;  
  6.     }  
  7.     public synchronized void take() throws InterruptedException {  
  8.         while (this.signals == bound)  
  9.             wait();  
  10.         this.signals++;  
  11.         this.notify();  
  12.     }  
  13.     public synchronized void release() throws InterruptedException {  
  14.         while (this.signals == 0)  
  15.             wait();  
  16.         this.signals--;  
  17.         this.notify();  
  18.     }  
  19. }  

 

當已經產生的信號數量達到了上限,take方法將阻塞新的信號產生請求,直到某個線程調用release方法後,被阻塞於take方法的線程才能傳遞自己的信號。

 

把Semaphore當鎖來使用
當信號量的數量上限是1時,Semaphore可以被當做鎖來使用。通過take和release方法來保護關鍵區域。

 

請您到ITEYE網站看 java小強 原創,謝謝!

http://cuisuqiang.iteye.com/ !

發佈了86 篇原創文章 · 獲贊 13 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章