Semaphore 通常用於限制可以訪問某些資源(物理或邏輯的)的線程數目。自從5.0開始,jdk在java.util.concurrent包裏提供了Semaphore 的官方實現,因此大家不需要自己去實現Semaphore。
下面的類使用信號量控制對內容池的訪問:
- import java.util.concurrent.Semaphore;
- class Pool {
- private static final int MAX_AVAILABLE = 100;
- private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
- public Object getItem() throws InterruptedException {
- available.acquire(); // 從此信號量獲取一個許可,在提供一個許可前一直將線程阻塞,否則線程被中斷
- return getNextAvailableItem();
- }
- public void putItem(Object x) {
- if (markAsUnused(x))
- available.release(); // 釋放一個許可,將其返回給信號量
- }
- // 僅作示例參考,非真實數據
- protected Object[] items = null;
- protected boolean[] used = new boolean[MAX_AVAILABLE];
- protected synchronized Object getNextAvailableItem() {
- for (int i = 0; i < MAX_AVAILABLE; ++i) {
- if (!used[i]) {
- used[i] = true;
- return items[i];
- }
- }
- return null;
- }
- protected synchronized boolean markAsUnused(Object item) {
- for (int i = 0; i < MAX_AVAILABLE; ++i) {
- if (item == items[i]) {
- if (used[i]) {
- used[i] = false;
- return true;
- } else
- return false;
- }
- }
- return false;
- }
- }
雖然JDK已經提供了相關實現,但是還是很有必要去熟悉如何使用Semaphore及其背後的原理。
做一個簡單的Semaphore實現:
- class SemaphoreTest {
- private boolean signal = false;
- public synchronized void take() {
- this.signal = true;
- this.notify();
- }
- public synchronized void release() throws InterruptedException {
- while (!this.signal)
- wait();
- this.signal = false;
- }
- }
使用這個semaphore可以避免錯失某些信號通知。用take方法來代替notify,release方法來代替wait。如果某線程在調用release等待之前調用take方法,那麼調用release方法的線程仍然知道take方法已經被某個線程調用過了,因爲該Semaphore內部保存了take方法發出的信號。而wait和notify方法就沒有這樣的功能。
可計數的Semaphore:
- class SemaphoreTest {
- private int signals = 0;
- public synchronized void take() {
- this.signals++;
- this.notify();
- }
- public synchronized void release() throws InterruptedException {
- while (this.signals == 0)
- wait();
- this.signals--;
- }
- }
Semaphore上限:
- class SemaphoreTest {
- private int signals = 0;
- private int bound = 0;
- public SemaphoreTest(int upperBound) {
- this.bound = upperBound;
- }
- public synchronized void take() throws InterruptedException {
- while (this.signals == bound)
- wait();
- this.signals++;
- this.notify();
- }
- public synchronized void release() throws InterruptedException {
- while (this.signals == 0)
- wait();
- this.signals--;
- this.notify();
- }
- }
當已經產生的信號數量達到了上限,take方法將阻塞新的信號產生請求,直到某個線程調用release方法後,被阻塞於take方法的線程才能傳遞自己的信號。
把Semaphore當鎖來使用:
當信號量的數量上限是1時,Semaphore可以被當做鎖來使用。通過take和release方法來保護關鍵區域。
請您到ITEYE網站看 java小強 原創,謝謝!