2

我可以看到如何在Java中實現「標準」Semaphore類。但是,我不知道如何在Java中實現二進制信號量類。這種實現如何工作?我應該何時調用wake和notify方法來喚醒和停止信號量上的線程? 我明白什麼是二進制信號量,但我不知道如何對它們進行編碼。如何在Java中實現二進制信號量類?

編輯注:意識到我說「BINARY」信號量類。標準的Semaphore類我已經做了,我知道它是正確的,所以標準的Semaphore類對我不感興趣。

+0

你有沒有嘗試過;以現有信號燈類的源代碼,它會如何表現,如果它是隻需要1。 – Scorpion

+0

許可你看了(例如維基百科)的定義(二進制)信號量?你能解釋爲什麼給出的答案(特別是Vikas的答案或亞歷山大的更廣泛的答案)是不夠的?否則,你可以嘗試解釋用例(爲了什麼*目的*你需要二進制信號量/互斥量嗎?) –

回答

3

我想你說的是互斥鎖(或互斥鎖)。如果是這樣,你可以使用內部鎖。這種在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包內使用。

希望這會有所幫助。

+0

你所說的是我應該放什麼東西在二進制信號量的類。我已經知道了我應該做的,在某些時候,但我不知道我應該在哪裏呼叫通知和w ait電話。 – Victor

+0

你不需要深入研究這樣的細節(但是如果你願意,可以看看'sun.misc.Unsafe'類,就像我在文章中提到的那樣)。您可以通過派生的便利實現來實現您的目標。 – surlac

0

你可以看看的Java實現Semaphore類的源代碼(或者直接用它?)

+0

我需要二進制信號量而不是那個。 – Victor

2

這裏是直接從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

1

是的,你可以。具有單一許可證的信號量是二進制信號量。他們控制對單一資源的訪問。他們可以被看作是某種互斥/鎖。

Semaphore binarySemaphore = new Semaphore(1); 
+0

它沒有幫助,我需要一個二進制信號類,而不是標準的。 – Victor

+0

如果它只有一個許可證,它**是**二進制信號量。您的評論好像是說「這車不適合的:它可以上升到180公里/小時,而我需要去在90公里每小時 –

+0

可以擴展標準信號和下面創建自己的二進制信號類。 公共類BinarySemaphore延伸旗語{ BinarySemaphore(){ 超級(1);} } – Drona

3

下面是一個簡單的實現我做了一個二進制信號:

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

+0

這是不安全的 - 只有release()是同步的,所以如果acquire併發運行釋放,在if(countingSemaphore.availablePermits()!= 1)之後,以及調用釋放之前,最終可能會出現意外的行爲。此外,使獲取同步不會工作,因爲鎖然後鎖定,停止釋放二進制信號量,停止應用程序。 –

+0

@SamHeather我只是想着你說的話,如果非同步方法獲取開始就像你在!= 1檢查後說的那樣,將沒有可用的槽,並且內部的acquire-call會停止,並且線程會等待,上下文切換,另一個釋放線程可以繼續調用'countingSemaphore.release();' 只是想,如果這將是一個問題嗎?我認爲所有可能的請求線程都會卡在內核'countingSemaphore.acquire();'-call。你不這麼認爲嗎? 同步'release()' - 方法只是避免了太多的空閒插槽。 – Dunstkreis

0

我有我自己的實施二進制信號在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); 
    } 
} 

告訴我,如果你發現代碼中有任何錯誤,但到目前爲止,它總是正常工作! :)

0

我寧願使用Lock

除了命名匹配,Java的信號燈是沒有辦法實現BinarySemaphore,並使用對象等待/通知或同步是非常原始。

相反,Lock類提供的鎖定語義與Semaphore鎖定/解鎖(與Semaphore的獲取/釋放相比)幾乎相同,但它專門用於解決臨界區域功能,只需要一個線程立即進入。

值得注意的鎖還提供感謝超時語義嘗試tryLock方法。