我可以看到如何在Java中實現「標準」Semaphore類。但是,我不知道如何在Java中實現二進制信號量類。這種實現如何工作?我應該何時調用wake和notify方法來喚醒和停止信號量上的線程? 我明白什麼是二進制信號量,但我不知道如何對它們進行編碼。如何在Java中實現二進制信號量類?
編輯注:意識到我說「BINARY」信號量類。標準的Semaphore類我已經做了,我知道它是正確的,所以標準的Semaphore類對我不感興趣。
我可以看到如何在Java中實現「標準」Semaphore類。但是,我不知道如何在Java中實現二進制信號量類。這種實現如何工作?我應該何時調用wake和notify方法來喚醒和停止信號量上的線程? 我明白什麼是二進制信號量,但我不知道如何對它們進行編碼。如何在Java中實現二進制信號量類?
編輯注:意識到我說「BINARY」信號量類。標準的Semaphore類我已經做了,我知道它是正確的,所以標準的Semaphore類對我不感興趣。
我想你說的是互斥鎖(或互斥鎖)。如果是這樣,你可以使用內部鎖。這種在Java中的行爲鎖的互斥體,這意味着最多隻有一個線程可以擁有鎖:
synchronized (lock) {
// Access or modify shared state guarded by lock
}
如果鎖是一個模擬對象,僅用於鎖定使用。
編輯:
這是給你一個實現 - 它使用的零值表示未鎖定狀態非再進入的互斥鎖類,以及一個代表鎖定狀態。
class Mutex implements Lock, java.io.Serializable {
// Our internal helper class
private static class Sync extends AbstractQueuedSynchronizer {
// Report whether in locked state
protected boolean isHeldExclusively() {
return getState() == 1;
}
// Acquire the lock if state is zero
public boolean tryAcquire(int acquires) {
assert acquires == 1; // Otherwise unused
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// Release the lock by setting state to zero
protected boolean tryRelease(int releases) {
assert releases == 1; // Otherwise unused
if (getState() == 0) throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// Provide a Condition
Condition newCondition() { return new ConditionObject(); }
// Deserialize properly
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
// The sync object does all the hard work. We just forward to it.
private final Sync sync = new Sync();
public void lock() { sync.acquire(1); }
public boolean tryLock() { return sync.tryAcquire(1); }
public void unlock() { sync.release(1); }
public Condition newCondition() { return sync.newCondition(); }
public boolean isLocked() { return sync.isHeldExclusively(); }
public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
}
如果你需要知道你應該在哪裏叫wait()
和notify()
,看看sun.misc.Unsafe#park()
。 ( - LockSupport < - 不安全的AbstractQueuedSynchronizer <)它的java.util.concurrent.locks包內使用。
希望這會有所幫助。
這裏是直接從Java site
併發實用程序庫,由Doug Lea領導的JSR-166是一個 專門發佈的J2SE 5.0平臺中的流行併發程序包。它提供了強大的高級線程結構,其中包括執行程序,它們是線程任務框架,線程安全的 隊列,定時器,鎖(包括原子的),以及其他 同步原語。
一個這樣的鎖是衆所周知的信號量。信號量可以用於 ,與現在使用等待的方式相同,用於限制對代碼塊的訪問。信號量更加靈活,並且還可以允許多個併發線程訪問,並允許您在 獲取它之前測試鎖。以下示例僅使用一個信號量,也稱爲二進制信號量,即 。有關更多信息,請參閱java.util.concurrent包中的 。
final private Semaphore s= new Semaphore(1, true);
s.acquireUninterruptibly(); //for non-blocking version use s.acquire()
try {
balance=balance+10; //protected value
} finally {
s.release(); //return semaphore token
}
我認爲,採用更高級別的摘要,例如Semaphore類的全部原因是,你不必叫低水平wait
/notify
。
是的,你可以。具有單一許可證的信號量是二進制信號量。他們控制對單一資源的訪問。他們可以被看作是某種互斥/鎖。
Semaphore binarySemaphore = new Semaphore(1);
下面是一個簡單的實現我做了一個二進制信號:
public class BinarySemaphore {
private final Semaphore countingSemaphore;
public BinarySemaphore(boolean available) {
if (available) {
countingSemaphore = new Semaphore(1, true);
} else {
countingSemaphore = new Semaphore(0, true);
}
}
public void acquire() throws InterruptedException {
countingSemaphore.acquire();
}
public synchronized void release() {
if (countingSemaphore.availablePermits() != 1) {
countingSemaphore.release();
}
}
}
該實現二進制信號,你不能用計數信號,只有有一個許可證獲得一個屬性 - 多個呼叫釋放仍將只留下一個資源。這個屬性被提到here。
這是不安全的 - 只有release()是同步的,所以如果acquire併發運行釋放,在if(countingSemaphore.availablePermits()!= 1)之後,以及調用釋放之前,最終可能會出現意外的行爲。此外,使獲取同步不會工作,因爲鎖然後鎖定,停止釋放二進制信號量,停止應用程序。 –
@SamHeather我只是想着你說的話,如果非同步方法獲取開始就像你在!= 1檢查後說的那樣,將沒有可用的槽,並且內部的acquire-call會停止,並且線程會等待,上下文切換,另一個釋放線程可以繼續調用'countingSemaphore.release();' 只是想,如果這將是一個問題嗎?我認爲所有可能的請求線程都會卡在內核'countingSemaphore.acquire();'-call。你不這麼認爲嗎? 同步'release()' - 方法只是避免了太多的空閒插槽。 – Dunstkreis
我有我自己的實施二進制信號在Java中的。
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* A binary semaphore extending from the Java implementation {@link Semaphore}.
* <p>
* This semaphore acts similar to a mutex where only one permit is acquirable. Attempts to acquire or release more than one permit
* are forbidden.
* <p>
* Has in {@link Semaphore}, there is no requirement that a thread that releases a permit must have acquired that permit. However,
* no matter how many times a permit is released, only one permit can be acquired at a time. It is advised that the program flow
* is such that the thread making the acquiring is the same thread making the release, otherwise you may end up having threads
* constantly releasing this semaphore, thus rendering it ineffective.
*
* @author Pedro Domingues
*/
public final class BinarySemaphore extends Semaphore {
private static final long serialVersionUID = -927596707339500451L;
private final Object lock = new Object();
/**
* Creates a {@code Semaphore} with the given number of permits between 0 and 1, and the given fairness setting.
*
* @param startReleased
* <code>true</code> if this semaphore starts with 1 permit or <code>false</code> to start with 0 permits.
* @param fairMode
* {@code true} if this semaphore will guarantee first-in first-out granting of permits under contention, else
* {@code false}
*/
public BinarySemaphore(boolean startReleased, boolean fairMode) {
super((startReleased ? 1 : 0), fairMode);
}
@Override
public void acquire(int permits) throws InterruptedException {
if (permits > 1)
throw new UnsupportedOperationException("Cannot acquire more than one permit!");
else
super.acquire(permits);
}
@Override
public void acquireUninterruptibly(int permits) {
if (permits > 1)
throw new UnsupportedOperationException("Cannot acquire more than one permit!");
else
super.acquireUninterruptibly(permits);
}
@Override
public void release() {
synchronized (lock) {
if (this.availablePermits() == 0)
super.release();
}
}
@Override
public void release(int permits) {
if (permits > 1)
throw new UnsupportedOperationException("Cannot release more than one permit!");
else
this.release();
}
@Override
public boolean tryAcquire(int permits) {
if (permits > 1)
throw new UnsupportedOperationException("Cannot acquire more than one permit!");
else
return super.tryAcquire(permits);
}
@Override
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException {
if (permits > 1)
throw new UnsupportedOperationException("Cannot release more than one permit!");
else
return super.tryAcquire(permits, timeout, unit);
}
}
告訴我,如果你發現代碼中有任何錯誤,但到目前爲止,它總是正常工作! :)
你有沒有嘗試過;以現有信號燈類的源代碼,它會如何表現,如果它是隻需要1。 – Scorpion
許可你看了(例如維基百科)的定義(二進制)信號量?你能解釋爲什麼給出的答案(特別是Vikas的答案或亞歷山大的更廣泛的答案)是不夠的?否則,你可以嘗試解釋用例(爲了什麼*目的*你需要二進制信號量/互斥量嗎?) –