本文介紹的Semaphore實現基於synchronized,wait()和notify/notifyAll(),這是java並發包之前的典型實現方式.在eclipse的源碼中可以找到不少這樣的案例,下文中也會把eclipse中的幾個實現類作為案例以分析之.
注,這里介紹的信號量實現是基於java語言機制,用於實現多線程間的同步操作,所以對S,P(S),V(S)等概念的介紹將結合本文內容,做合適的調整,讀者可閱讀操作系統相關書籍的信號量章節獲取標准定義.
*本文內容
---信號量簡介
---典型案例
*Semaphore概述
---通常把一個非負整數稱為Semaphore,表示為S.
S可以理解為可用的資源數量.這里不涉及進程問題,所以就假定S>=0.
---S實現的同步機制表示為PV原語操作
P(S):若S=0,線程進入等待隊列;否則,—S;
V(S):++S,喚醒處於等待中的線程.
(注,P是荷蘭語的Passeren,相當於英文的pass, V是荷蘭語的Verhoog,相當於英文中的incremnet).
*案例
1)典型實現
這段程序源自ibm的一本並發書籍,實現了計數信號量{S|S∈{0,N}}和二元信號量(S={0,1})
S示例public abstract class Semaphore {
private int value = 0;
public Semaphore() {
}
public Semaphore(int initial) {
if (initial >= 0)
value = initial;
else
throw new IllegalArgumentException("initial < 0");
}
public final synchronized void P() throws InterruptedException {
while (value == 0)
wait();
value--;
}
protected final synchronized void Vc() {
value++;
notifyAll();
}
protected final synchronized void Vb() {
value++;
notifyAll();
if (value > 1)
value = 1;
}
public abstract void V();
public String toString() {
return ".value=" + value;
}
}
public final class BinarySemaphore extends Semaphore {
public BinarySemaphore() {
super();
}
public BinarySemaphore(int initial) {
super(initial);
if (initial > 1)
throw new IllegalArgumentException("initial > 1");
}
public final synchronized void V() {
super.Vb();
}
}
public final class CountingSemaphore extends Semaphore {
public CountingSemaphore() {
super();
}
public CountingSemaphore(int initial) {
super(initial);
}
public final synchronized void V() {
super.Vc();
}
}
2)實現讀寫鎖
eclipse使用它,解決日志操作相關類在map,數組中的同步問題.
ReadWriteLock/******************************************************************************* * Copyright (c) 2008, 2011 IBM Corporation and others * All rights reserved. This program and the accompanying materials are made * available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html ******************************************************************************/
package org.eclipse.equinox.log.internal;
public class BasicReadWriteLock {
private int currentReaders = 0;
private int writersWaiting = 0;
private boolean writing = false;
public synchronized void readLock() {
while (writing || writersWaiting != 0) {
try {
wait();
} catch (InterruptedException e) {
// reset interrupted state but keep waiting
Thread.currentThread().interrupt();
}
}
currentReaders++;
}
public synchronized void readUnlock() {
currentReaders--;
notifyAll();
}
public synchronized void writeLock() {
writersWaiting++;
while (writing || currentReaders != 0) {
try {
wait();
} catch (InterruptedException e) {
// reset interrupted state but keep waiting
Thread.currentThread().interrupt();
}
}
writersWaiting--;
writing = true;
}
public synchronized void writeUnlock() {
writing = false;
notifyAll();
}
}
3)延遲信號量
這個信號量的亮點在acquire(long delay).
靈活的Semaphore/******************************************************************************* * Copyright (c) 2003, 2006 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/
package org.eclipse.core.runtime.internal.adaptor;
/** * Internal class. */
public class Semaphore {
protected long notifications;
public Semaphore(int count) {
notifications = count;
}
/** * Attempts to acquire this semaphore. Returns only when the semaphore has been acquired. */
public synchronized void acquire() {
while (true) {
if (notifications > 0) {
notifications--;
return;
}
try {
wait();
} catch (InterruptedException e) {
//Ignore
}
}
}
/** * Attempts to acquire this semaphore. Returns true if it was successfully acquired, * and false otherwise. */
public synchronized boolean acquire(long delay) { //若傳入負數,用於判斷是否資源已被占
long start = System.currentTimeMillis();
long timeLeft = delay;
while (true) {
if (notifications > 0) {
notifications--;
return true;
}
if (timeLeft <= 0) //在延遲后不再繼續嘗試獲取鎖
return false;
try {
wait(timeLeft);
} catch (InterruptedException e) {
//Ignore
}
timeLeft = start + delay - System.currentTimeMillis();
}
}
public synchronized void release() {
notifications++;
notifyAll();
}
// for debug only
public String toString() {
return "Semaphore(" + notifications + ")"; //$NON-NLS-1$ //$NON-NLS-2$
}
*總結
---通過java的對象鎖,wait/notify機制模擬的信號量,可以呈現多種形態以應對各種的互斥需求.
---本文給出的例子,具有普遍的適用性.在實踐中,咱們可以根據需求定制各種信號量實現.
---jdk1.5提供了Semaphore的另一種實現機制.