ConcurrentSkipListSet Source Analysis of Dead Javaa Collection - Set Summary

Keywords: Java less

problem

(1) Is the bottom of the ConcurrentSkipListSet a ConcurrentSkipListMap?

(2) Is the ConcurrentSkipListSet thread safe?

(3) Is the ConcurrentSkipListSet ordered?

(4) How is the ConcurrentSkipListSet different from the previous Set?

brief introduction

The bottom level of the ConcurrentSkipListSet is implemented through ConcurrentNavigableMap, which is an ordered collection of thread security.

Source Code Analysis

Its source code is simple, basically identical to the Set implemented through Map, but there are a few more ways to get the closest element.

To preserve the integrity of the column, I'll stick to the source code and finally compare the entire family of Set s, pulling those interested directly to the bottom.

// Implements the NavigableSet interface without the so-called ConcurrentNavigableSet interface
public class ConcurrentSkipListSet<E>
    extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable {

    private static final long serialVersionUID = -2479143111061671589L;

    // Store map s used
    private final ConcurrentNavigableMap<E,Object> m;

    // Initialization
    public ConcurrentSkipListSet() {
        m = new ConcurrentSkipListMap<E,Object>();
    }

    // Incoming Comparator
    public ConcurrentSkipListSet(Comparator<? super E> comparator) {
        m = new ConcurrentSkipListMap<E,Object>(comparator);
    }

    // Initialize map using ConcurrentSkipListMap
    // And put all the elements in the set c into the map
    public ConcurrentSkipListSet(Collection<? extends E> c) {
        m = new ConcurrentSkipListMap<E,Object>();
        addAll(c);
    }

    // Initialize map using ConcurrentSkipListMap
    // And put all the elements in the ordered Set into the map
    public ConcurrentSkipListSet(SortedSet<E> s) {
        m = new ConcurrentSkipListMap<E,Object>(s.comparator());
        addAll(s);
    }

    // Used when returning a child set inside the ConcurrentSkipListSet class
    ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) {
        this.m = m;
    }

    // Cloning Method
    public ConcurrentSkipListSet<E> clone() {
        try {
            @SuppressWarnings("unchecked")
            ConcurrentSkipListSet<E> clone =
                (ConcurrentSkipListSet<E>) super.clone();
            clone.setMap(new ConcurrentSkipListMap<E,Object>(m));
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new InternalError();
        }
    }

    /* ---------------- Set operations -------------- */
    // Returns the number of elements
    public int size() {
        return m.size();
    }

    // Check if empty
    public boolean isEmpty() {
        return m.isEmpty();
    }

    // Check to see if an element is included
    public boolean contains(Object o) {
        return m.containsKey(o);
    }

    // Add an element
    // Call map's putIfAbsent() method
    public boolean add(E e) {
        return m.putIfAbsent(e, Boolean.TRUE) == null;
    }

    // Remove an element
    public boolean remove(Object o) {
        return m.remove(o, Boolean.TRUE);
    }

    // Empty all elements
    public void clear() {
        m.clear();
    }

    // iterator
    public Iterator<E> iterator() {
        return m.navigableKeySet().iterator();
    }

    // Descending iterator
    public Iterator<E> descendingIterator() {
        return m.descendingKeySet().iterator();
    }

    /* ---------------- AbstractSet Overrides -------------- */
    // Comparative equality and other methods
    public boolean equals(Object o) {
        // Override AbstractSet version to avoid calling size()
        if (o == this)
            return true;
        if (!(o instanceof Set))
            return false;
        Collection<?> c = (Collection<?>) o;
        try {
            // Here's a comparison through two two layers of for loops
            // There is a lot of room for optimizing, refer to the egg in the CopyOnWriteArraySet article above
            return containsAll(c) && c.containsAll(this);
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }
    }

    // Remove all elements from set c
    public boolean removeAll(Collection<?> c) {
        // Override AbstractSet version to avoid unnecessary call to size()
        boolean modified = false;
        for (Object e : c)
            if (remove(e))
                modified = true;
        return modified;
    }

    /* ---------------- Relational operations -------------- */

    // Maximum element less than e
    public E lower(E e) {
        return m.lowerKey(e);
    }

    // The largest element less than or equal to e
    public E floor(E e) {
        return m.floorKey(e);
    }

    // The smallest element greater than or equal to e
    public E ceiling(E e) {
        return m.ceilingKey(e);
    }

    // Minimum element greater than e
    public E higher(E e) {
        return m.higherKey(e);
    }

    // Pop up the smallest element
    public E pollFirst() {
        Map.Entry<E,Object> e = m.pollFirstEntry();
        return (e == null) ? null : e.getKey();
    }

    // Pop up the biggest element
    public E pollLast() {
        Map.Entry<E,Object> e = m.pollLastEntry();
        return (e == null) ? null : e.getKey();
    }

    /* ---------------- SortedSet operations -------------- */

    // Comparator
    public Comparator<? super E> comparator() {
        return m.comparator();
    }

    // The smallest element
    public E first() {
        return m.firstKey();
    }

    // The largest element
    public E last() {
        return m.lastKey();
    }

    // Take a child set between two elements
    public NavigableSet<E> subSet(E fromElement,
                                  boolean fromInclusive,
                                  E toElement,
                                  boolean toInclusive) {
        return new ConcurrentSkipListSet<E>
            (m.subMap(fromElement, fromInclusive,
                      toElement,   toInclusive));
    }

    // Header set
    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
        return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
    }

    // Tail set
    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
        return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
    }

    // Sub set, containing from, not to
    public NavigableSet<E> subSet(E fromElement, E toElement) {
        return subSet(fromElement, true, toElement, false);
    }

    // Header Sub set, does not contain to
    public NavigableSet<E> headSet(E toElement) {
        return headSet(toElement, false);
    }

    // Tail set, containing from
    public NavigableSet<E> tailSet(E fromElement) {
        return tailSet(fromElement, true);
    }

    // Descending set
    public NavigableSet<E> descendingSet() {
        return new ConcurrentSkipListSet<E>(m.descendingMap());
    }

    // A divisible iterator
    @SuppressWarnings("unchecked")
    public Spliterator<E> spliterator() {
        if (m instanceof ConcurrentSkipListMap)
            return ((ConcurrentSkipListMap<E,?>)m).keySpliterator();
        else
            return (Spliterator<E>)((ConcurrentSkipListMap.SubMap<E,?>)m).keyIterator();
    }

    // Atomic update map, use for clone method
    private void setMap(ConcurrentNavigableMap<E,Object> map) {
        UNSAFE.putObjectVolatile(this, mapOffset, map);
    }

    // Atomic operations related content
    private static final sun.misc.Unsafe UNSAFE;
    private static final long mapOffset;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> k = ConcurrentSkipListSet.class;
            mapOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("m"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }
}

As you can see, ConcurrentSkipListSet s are basically implemented using ConcurrentSkipListMap. Although the sub set is partially implemented using internal classes in ConcurrentSkipListMap, these internal classes are also related to ConcurrentSkipListMap and return part of the ConcurrentSkipListMap data.

In addition, the equals() method here is fairly pervasive and has a lot of room for optimization, so the author knows that few people call the equals() method.

summary

(1) ConcurrentSkipListSet is implemented using ConcurrentNavigableMap at the bottom;

(2) ConcurrentSkipListSet is ordered, based on the natural ordering of elements or the order determined by the comparator;

(3) ConcurrentSkipListSet is thread-safe;

Eggs

Set Summary:

Set Orderliness Thread Security Bottom level implementation Key interfaces Characteristic
HashSet nothing no HashMap nothing simple
LinkedHashSet Yes no LinkedHashMap nothing Insertion order
TreeSet Yes no NavigableMap NavigableSet Natural order
CopyOnWriteArraySet Yes yes CopyOnWriteArrayList nothing Insert order, read-write separation
ConcurrentSkipListSet Yes yes ConcurrentNavigableMap NavigableSet Natural order

From this we can find some rules:

(1) All Sets except HashSet are ordered;

(2) The implementation of NavigableSet or SortedSet interfaces is in natural order;

(3) Sets implemented using a Set of concurrent security are also concurrent security;

(4) Although not all TreeSet s are implemented using TreeMap, they are all related to TreeMap (TreeMap is combined in a submap of TreeMap);

(5) ConcurrentSkipListSet, although not all are implemented using ConcurrentSkipListMap, is actually related to ConcurrentSkipListMap (ConcurrentSkipListMap is a combination of ConcurrentSkipListMap in the submaps of ConcurrentSkipListeMap);

Welcome to pay attention to my public number "Tong Gong Read Source". Check out more articles about source series and enjoy the sea of source code with Tong Gong.

Posted by amitkrathi on Mon, 06 May 2019 23:40:38 -0700