2016-05-04 179 views
2

我剛剛實現了一個信號量的自定義阻塞隊列。阻塞隊列實現

由於我無法找到的原因,當我的隊列爲空時,我的隊列沒有被信號燈阻塞。

這裏是我的實現:

package poolThread; 

import java.util.LinkedList; 
import java.util.Queue; 
import java.util.concurrent.Semaphore; 

public class MyQueue<E> { 
Semaphore s = new Semaphore(0, true); 
private Queue<E> queue = new LinkedList<E>(); 


public boolean isEmpty(){ 
    return this.queue.isEmpty(); 
} 
public void enqueue(E e){ 
    queue.add(e); 
    s.release(); 
} 
public E dequeue(){ 
    E e = null; 
    try { 
     s.acquire(); 
    } catch (InterruptedException e1) { 
     // TODO Auto-generated catch block 
     e1.printStackTrace(); 
    } 
    e = queue.remove(); 
    return e; 

} 

}

你能幫我找到我的代碼錯?

+0

?當你的隊列爲空時,這*會阻塞。 –

+0

它只是有時,我用這個阻塞隊列來實現一個線程池,當我運行幾個線程它不會阻塞。 – gil

+0

我也使用了ArrayBlockingQueue的java實現,而不是我的爲了檢查它是否工作,它確實有效,所以我很確定問題出在我的阻塞隊列實現中。 – gil

回答

2

這裏的問題是LinkedList - 它不是線程安全的。因此,即使正確獲得許可證,LinkedList上的remove()操作也會(並將)導致麻煩。這裏有一個簡單的「測試案例」,顯示的行爲:

MyQueue<String> x = new MyQueue<>(); 

ExecutorService es = Executors.newFixedThreadPool(2); 
for (int j = 0; j < 2; j++) 
    es.submit(() -> { 
     String tn = Thread.currentThread().getName(); 
     for (int i = 0; i < 2; i++) 
      x.enqueue("v" + i); 

     for (int i = 0; i < 2; i++) 
      System.out.println(tn + " deq: " + x.dequeue()); 
    }); 

輸出會像(你會看到,由於null s到NoSuchElementException S於該remove法):

pool-1-thread-2 deq: v0 
pool-1-thread-1 deq: null 

最簡單解決方案將取代LinkedListjava.util.concurrent.ConcurrentLinkedQueue

+0

我所有的想法背後的實現是實現我的自我線程安全的一切,並從中學習,而不是使用java線程安全元素。你有什麼建議,我如何實現它沒有併發鏈表? – gil

+0

@gilleibovitz那麼你將不得不確保列表訪問只發生在'synchronized'塊中或使用'Lock'。參見[here](http://tutorials.jenkov.com/java-concurrency/locks.html)以獲取更多信息 – nyname00

+0

@gilleibovitz:或者使用Collections.sychronizedList,這是Java Concurrency in Practice中的示例。 –