2016-02-03 76 views
2

我想知道是否可以使用Semaphore來實現阻塞隊列?我可以在Java中使用Semaphore實現阻塞隊列嗎?

在下面的代碼,我使用一個信號量,以保護關鍵部分,和兩個信號量更多的對象跟蹤空時隙和填充的對象的數量。

public class BlockingQueue { 
    private List<Object> queue = new LinkedList<Object>(); 
    private int limit; 
    private Semaphore slots; // semaphore for empty slots 
    private Semaphore objs; // semaphore for filled slots 
    private Semaphore mutex; // for the critical section 
    public BlockingQueue(int limit) { 
    this.limit = limit; 
    this.slots = new Semaphore(limit); // initial empty slot = capacity 
    this.objs = new Semaphore(0); 
    this.mutex = new Semaphore(1); 
    } 
    private void enqueue(Object o) throws InterruptedException { 
    slots.acquire(); 
    mutex.acquire(); // critical section starts 
    queue.add(o); 
    mutex.release(); // critical section ends 
    objs.release(); 
    } 
    private Object dequeue() throws InterruptedException { 
    objs.acquire(); 
    mutex.acquire(); // critical section starts 
    Object o = queue.remove(0); 
    mutex.release(); // critical section ends 
    slots.release(); 
    return o; 
    } 
} 
+1

爲什麼你想爲[推倒重來(https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html)?順便說一下:信號量不是一個互斥體,也不是一個「關鍵部分」。這兩個條款有完全不同的含義 – specializt

+0

@specializt其實我之前問這個問題的採訪,所以我試圖找出如何自己做。我知道Semaphore不是互斥體,也不是關鍵部分。我只是說我正在使用名爲mutex的Semaphore來保護關鍵部分。對不清楚的描述抱歉。 –

+1

你的代碼中沒有關鍵部分......還有:要求你重新實現已存在的東西的僱主應該不惜一切代價避免......只是說。事實上,尋找那些重新使用久經考驗的穩定庫的員工是可取的,而不是重寫所有內容,因爲這大大加快了開發速度 - 它也提高了軟件質量。 – specializt

回答

1

添加到先前的評論 - 我們可以同意你的代碼的工作(這是一個衆所周知的算法),尤其是你在保護LinkedList的正確的,因爲它不是內部線程安全的。

然而,如果你的util實施http://grepcode.com/file_/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/concurrent/ArrayBlockingQueue.java/?v=source 你的代碼比較了Java它可能會帶來一些需要考慮的要點:

  1. 請谷歌「與二進制信號的ReentrantLock」上的討論:他們都創造互斥&保護關鍵部分,但前者更好地描述你的意圖,再加上它可能是未來維護更加容易。例如,一位程序員不會意外地通過未獲取它的線程釋放ReentrantLock

  2. Google討論「信號量與條件變量」:兩者都允許您「等待某些東西變得可用」,但條件變量可能更一般,再加上你可以將所有的條件綁定到一個單獨的鎖(就像java util代碼那樣)。我認爲這對性能有一定的影響較小,再加上你的方式將需要接近未來的要求,例如中斷,超時,崩潰。這不會讓你的代碼「錯誤」,這只是你需要考慮的事情。

+1

'ArrayBlockingQueue'是一個很好的參考OP的保護風格實施,但不是一個很好的例子,如何變成一個鏈表進入併發隊列。 Semaphore將在內部使用(如果由平臺提供)的原子比較和交換是最乾淨和有效的方式。請參閱'ConcurrentLinkedQueue'源代碼。 –

+0

鎖和二進制信號燈不會「保護」關鍵部分,甚至沒有任何意義 - 部分不能在任何程度上「受到保護」,它們在大多數情況下超出正常應用的範圍(當然有例外) – specializt

+0

大!我會閱讀這些參考資料。順便說一句,「Reentrant」的名字是什麼意思? –

1

沒有測試,我會說這個工程。 但是,每個release()都會通知acquire()中被阻塞的線程。所以你真的至少有與重入鎖+條件相同的成本,可能更糟,因爲有2個獲取和2個發佈()調用。