2016-05-04 14 views
2

Ich habe gerade eine benutzerdefinierte blockierende Warteschlange mit einem Semaphor implementiert.blockieren Queue-Implementierung

aus einem Grund, den ich nicht finden kann, wird meine Warteschlange nicht vom Semaphor blockiert, wenn meine Warteschlange leer ist.

hier ist meine Umsetzung:

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; 

} 

}

könnten Sie mir helfen, den Fehler in meinem Code?

+0

? Dies * blockiert *, wenn Ihre Warteschlange leer ist. –

+0

es tut nur manchmal, ich habe diese blockierende Warteschlange verwendet, um einen Threadpool zu implementieren, und wenn ich einige Threads ausführen, blockiert es nicht. – gil

+0

Ich habe auch die Java-Implementierung von ArrayBlockingQueue statt meiner verwendet, um zu überprüfen, ob es funktioniert und es funktioniert, also bin ich mir ziemlich sicher, dass das Problem in meiner blockierenden Queue-Implementierung ist. – gil

Antwort

2

Das Problem hier ist die LinkedList - die nicht Thread-sicher ist. Selbst wenn die Genehmigungen korrekt erfasst werden, kann (und wird) die remove() Operation auf der LinkedList Probleme verursachen. Hier ist ein einfacher „Testfall“, das Verhalten zu zeigen:

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()); 
    }); 

Der Ausgang wird etwas sein, wie (Sie null s aufgrund NoSuchElementException s auf der remove Methode sehen):

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

Die einfachste Lösung hierfür wäre, Ihre LinkedList durch eine java.util.concurrent.ConcurrentLinkedQueue zu ersetzen.

+0

meine ganze idee hinter der implementation ist, alles selbst zu implementieren, um threadsicher zu sein und daraus zu lernen und kein java thread safe element zu verwenden. Hast du irgendwelche Vorschläge für mich, wie man es ohne die gleichzeitige verknüpfte Liste umsetzt? – gil

+0

@gilleibovitz und dann müssen Sie sicherstellen, dass der Listenzugriff nur innerhalb eines "synchronisierten" Blocks erfolgt oder verwenden Sie ein 'Lock'. Weitere Informationen finden Sie unter [hier] (http://tutorials.jenkov.com/java-concurrency/locks.html) – nyname00

+0

@gilleibovitz: oder verwenden Sie Collections.symronizedList, was das Beispiel in Java Concurrency in Practice ist. –