Concurrent Set Queue

前端 未结 7 1665
情话喂你
情话喂你 2020-12-05 23:10

Maybe this is a silly question, but I cannot seem to find an obvious answer.

I need a concurrent FIFO queue that contains only unique values. Attempting to add a val

7条回答
  •  独厮守ぢ
    2020-12-05 23:49

    If you want better concurrency than full synchronization, there is one way I know of to do it, using a ConcurrentHashMap as the backing map. The following is a sketch only.

    public final class ConcurrentHashSet extends ForwardingSet
        implements Set, Queue {
      private enum Dummy { VALUE }
    
      private final ConcurrentMap map;
    
      ConcurrentHashSet(ConcurrentMap map) {
        super(map.keySet());
        this.map = Preconditions.checkNotNull(map);
      }
    
      @Override public boolean add(E element) {
        return map.put(element, Dummy.VALUE) == null;
      }
    
      @Override public boolean addAll(Collection newElements) {
        // just the standard implementation
        boolean modified = false;
        for (E element : newElements) {
          modified |= add(element);
        }
        return modified;
      }
    
      @Override public boolean offer(E element) {
        return add(element);
      }
    
      @Override public E remove() {
        E polled = poll();
        if (polled == null) {
          throw new NoSuchElementException();
        }
        return polled;
      }
    
      @Override public E poll() {
        for (E element : this) {
          // Not convinced that removing via iterator is viable (check this?)
          if (map.remove(element) != null) {
            return element;
          }
        }
        return null;
      }
    
      @Override public E element() {
        return iterator().next();
      }
    
      @Override public E peek() {
        Iterator iterator = iterator();
        return iterator.hasNext() ? iterator.next() : null;
      }
    }
    

    All is not sunshine with this approach. We have no decent way to select a head element other than using the backing map's entrySet().iterator().next(), the result being that the map gets more and more unbalanced as time goes on. This unbalancing is a problem both due to greater bucket collisions and greater segment contention.

    Note: this code uses Guava in a few places.

提交回复
热议问题