2011-03-08 10 views

Respuesta

0

Puede anular los métodos de agregar y poner de cualquier implementación de BlockingQueue<T> para verificar primero si el elemento ya está dentro de la cola, p.

@Override 
public boolean add(T elem) { 
    if (contains(elem)) 
     return true; 
    return super.add(elem); 
} 
+0

buena pero no óptima como la implementación BlockingQueue normal de contains() requiere un recorrido de toda la cola –

+0

yo diría "óptima" es subjetivo. A menos que gane la suya, la otra opción simple es la sugerida por Spike y es una compensación clásica de espacio vs. tiempo. Entonces, si bien podría argumentarse como la mejor solución dependiendo del uso, le doy mi voto a esto debido a su simplicidad. –

+7

si "óptimo" incluye correcto, entonces esta implementación fallaría ya que es una condición de carrera. – jtahlborn

4

Puede crear una nueva clase que componga una BlockingQueue, un Set y un candado. Cuando pones() pruebas contra el conjunto mientras mantienes un bloqueo que impide que se ejecute get(). Cuando obtiene(), elimina el elemento del conjunto para que pueda volver a colocarse() en el futuro.

-2
class BlockingSet extends ArrayBlockingQueue<E> { 
    /*Retain all other methods except put*/ 
    public void put(E o) throws InterruptedException { 
     if (!this.contains(o)){ 
     super.put(o); 
     } 
    } 
} 
+0

La implementación de 'contains' itera sobre la lista, esto sería realmente lento ... –

1

Una implementación cola de bloqueo respaldado por un conjunto de hash vinculados por el orden de iteración predecible y constante de tiempo Además, la eliminación y contiene operaciones:

There you go.

+0

Se siente muy lento. – horec

+0

@horec - ¿Esa sensación proviene de mirar el código o de intentarlo realmente? En cuanto al código, tuve la misma preocupación, pero realmente no he podido probar – forhas

+0

Su enlace está muerto :-( – rcomblen

1

escribí esta clase para resolver un problema similar:

/** 
* Linked blocking queue with {@link #add(Object)} method, which adds only element, that is not already in the queue. 
*/ 
public class SetBlockingQueue<T> extends LinkedBlockingQueue<T> { 

    private Set<T> set = Collections.newSetFromMap(new ConcurrentHashMap<>()); 

    /** 
    * Add only element, that is not already enqueued. 
    * The method is synchronized, so that the duplicate elements can't get in during race condition. 
    * @param t object to put in 
    * @return true, if the queue was changed, false otherwise 
    */ 
    @Override 
    public synchronized boolean add(T t) { 
     if (set.contains(t)) { 
      return false; 
     } else { 
      set.add(t); 
      return super.add(t); 
     } 
    } 

    /** 
    * Takes the element from the queue. 
    * Note that no synchronization with {@link #add(Object)} is here, as we don't care about the element staying in the set longer needed. 
    * @return taken element 
    * @throws InterruptedException 
    */ 
    @Override 
    public T take() throws InterruptedException { 
     T t = super.take(); 
     set.remove(t); 
     return t; 
    } 
} 
Cuestiones relacionadas