package java.util.concurrent;

import java.io.ObjectStreamField;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Spliterator;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.DoubleBinaryOperator;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
import java.util.function.LongBinaryOperator;
import java.util.function.ToDoubleBiFunction;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntBiFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongBiFunction;
import java.util.function.ToLongFunction;
import java.util.stream.Stream;

//并发安全HashMap CAS + synchronized

public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
        implements ConcurrentMap<K, V>, Serializable {
    private static final long serialVersionUID = 7249069246763182397L;

    /* ---------------- Constants -------------- */
    //最大容量
    private static final int MAXIMUM_CAPACITY = 1 << 30;

    //默认容量
    private static final int DEFAULT_CAPACITY = 16;

    //数组长度最大值
    static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    //为以前的版本所使用(兼容性),当前没有用上
    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;

    //负载因子
    private static final float LOAD_FACTOR = 0.75f;

    //桶数组中由链表转换为红黑树的阈值,9个开始转换为红黑树,树化阈值
    static final int TREEIFY_THRESHOLD = 8;

    //桶数组中由红黑树转变为链表的阈值
    static final int UNTREEIFY_THRESHOLD = 6;

    //最小树形化容量阈值:即 当哈希表中的容量 > 该值时,才允许树形化链表 (即 将链表 转换成红黑树)
    //因为当桶数组长度过短,应该resize,而不是树化
    //TREEIFY_THRESHOLD*4
    static final int MIN_TREEIFY_CAPACITY = 64;

    //每个传输步骤的最小重新绑定数。范围被细分以允许多个调整大小线程。
    // 此值用作下限,以避免重设器遇到过多的内存争用。该值至少应为默认容量。
    private static final int MIN_TRANSFER_STRIDE = 16;

    //cas算法的stamp的位数
    private static int RESIZE_STAMP_BITS = 16;

    //可以帮助调整大小的最大线程数
    private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;

    /**
     * The bit shift for recording size stamp in sizeCtl.
     */
    private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;

    //节点哈希字段的编码
    static final int MOVED = -1; // hash for forwarding nodes
    static final int TREEBIN = -2; // hash for roots of trees
    static final int RESERVED = -3; // hash for transient reservations
    static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash

    //cpu核心数
    static final int NCPU = Runtime.getRuntime().availableProcessors();

    //序列化兼容性
    private static final ObjectStreamField[] serialPersistentFields = {
            new ObjectStreamField("segments", Segment[].class),
            new ObjectStreamField("segmentMask", Integer.TYPE),
            new ObjectStreamField("segmentShift", Integer.TYPE)
    };

    /* ---------------- Nodes -------------- */

    //Node,桶数组
    static class Node<K, V> implements Map.Entry<K, V> {
        final int hash;
        final K key;
        volatile V val;
        volatile Node<K, V> next;

        Node(int hash, K key, V val, Node<K, V> next){
            this.hash = hash;
            this.key = key;
            this.val = val;
            this.next = next;
        }

        public final K getKey(){ return key; }

        public final V getValue(){ return val; }

        public final int hashCode(){ return key.hashCode() ^ val.hashCode(); }

        public final String toString(){ return key + "=" + val; }

        public final V setValue(V value){
            throw new UnsupportedOperationException();
        }

        public final boolean equals(Object o){
            Object k, v, u;
            Map.Entry<?, ?> e;
            return ((o instanceof Map.Entry) &&
                    (k = (e = (Map.Entry<?, ?>) o).getKey()) != null &&
                    (v = e.getValue()) != null &&
                    (k == key || k.equals(key)) &&
                    (v == (u = val) || v.equals(u)));
        }

        //
        Node<K, V> find(int h, Object k){
            Node<K, V> e = this;
            if(k != null){
                do {
                    K ek;
                    if(e.hash == h &&
                       ((ek = e.key) == k || (ek != null && k.equals(ek))))
                        return e;
                } while ((e = e.next) != null);
            }
            return null;
        }
    }

    /* ---------------- Static utilities -------------- */
    // 高16与低16位异或运算,HASH_BITS=0x7FFFFFFF  hash函数
    static final int spread(int h){
        return (h ^ (h >>> 16)) & HASH_BITS;
    }

    //找一个恰好比c的大的2的幂
    private static final int tableSizeFor(int c){
        int n = c - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

    // 比较器
    static Class<?> comparableClassFor(Object x){
        if(x instanceof Comparable){
            Class<?> c;
            Type[] ts, as;
            Type t;
            ParameterizedType p;
            if((c = x.getClass()) == String.class) // bypass checks
                return c;
            if((ts = c.getGenericInterfaces()) != null){
                for(int i = 0; i < ts.length; ++i){
                    if(((t = ts[i]) instanceof ParameterizedType) &&
                       ((p = (ParameterizedType) t).getRawType() ==
                        Comparable.class) &&
                       (as = p.getActualTypeArguments()) != null &&
                       as.length == 1 && as[0] == c) // type arg is c
                        return c;
                }
            }
        }
        return null;
    }

    // 比较器
    @SuppressWarnings({"rawtypes", "unchecked"}) // for cast to Comparable
    static int compareComparables(Class<?> kc, Object k, Object x){
        return (x == null || x.getClass() != kc ? 0 :
                ((Comparable) k).compareTo(x));
    }

    /* ---------------- Table element access -------------- */
    //寻找指定数组在内存中i位置的数据
    @SuppressWarnings("unchecked")
    static final <K, V> Node<K, V> tabAt(Node<K, V>[] tab, int i){
        return (Node<K, V>) U.getObjectVolatile(tab, ((long) i << ASHIFT) + ABASE);
    }

    //cas算法
    static final <K, V> boolean casTabAt(Node<K, V>[] tab, int i,
            Node<K, V> c, Node<K, V> v){
        return U.compareAndSwapObject(tab, ((long) i << ASHIFT) + ABASE, c, v);
    }

    //设置指定数组在内存中i位置的数据
    static final <K, V> void setTabAt(Node<K, V>[] tab, int i, Node<K, V> v){
        U.putObjectVolatile(tab, ((long) i << ASHIFT) + ABASE, v);
    }

    /* ---------------- Fields -------------- */
    transient volatile Node<K, V>[] table; //桶数组

    /**
     * The next table to use; non-null only while resizing.
     */
    private transient volatile Node<K, V>[] nextTable; //

    //基本计数器值,主要在没有争用时使用,但在表初始化竞争期间也用作回退。通过CAS更新。
    private transient volatile long baseCount;
    //桶数组初始化和,resize方法,-1表示初始化,-(1+正在调整大小的线程数)
    private transient volatile int sizeCtl;

    // 调整大小时要拆分的下一个表索引(加上一个)
    private transient volatile int transferIndex;

    // 调整大小和/或创建计数器单元格时使用的自旋锁(通过CAS锁定)
    private transient volatile int cellsBusy;

    //计数器数组。非空时,大小是2的幂
    private transient volatile CounterCell[] counterCells;

    // views
    private transient KeySetView<K, V> keySet;
    private transient ValuesView<K, V> values;
    private transient EntrySetView<K, V> entrySet;


    /* ---------------- Public operations -------------- */

    public ConcurrentHashMap(){
    }

    public ConcurrentHashMap(int initialCapacity){
        if(initialCapacity < 0)
            throw new IllegalArgumentException();
        int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
                MAXIMUM_CAPACITY :
                tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
        this.sizeCtl = cap;
    }

    // 基于已有map构造map
    public ConcurrentHashMap(Map<? extends K, ? extends V> m){
        this.sizeCtl = DEFAULT_CAPACITY;
        putAll(m);
    }

    public ConcurrentHashMap(int initialCapacity, float loadFactor){
        this(initialCapacity, loadFactor, 1);
    }

    public ConcurrentHashMap(int initialCapacity,
            float loadFactor, int concurrencyLevel){
        if(!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
            throw new IllegalArgumentException();
        if(initialCapacity < concurrencyLevel)   // Use at least as many bins
            initialCapacity = concurrencyLevel;   // as estimated threads
        long size = (long) (1.0 + (long) initialCapacity / loadFactor);
        int cap = (size >= (long) MAXIMUM_CAPACITY) ?
                MAXIMUM_CAPACITY : tableSizeFor((int) size);
        this.sizeCtl = cap;
    }

    public int size(){
        long n = sumCount();
        return ((n < 0L) ? 0 :
                (n > (long) Integer.MAX_VALUE) ? Integer.MAX_VALUE :
                        (int) n);
    }

    public boolean isEmpty(){
        return sumCount() <= 0L; // ignore transient negative values
    }

    public V get(Object key){
        Node<K, V>[] tab;
        Node<K, V> e, p;
        int n, eh;
        K ek;
        int h = spread(key.hashCode());
        if((tab = table) != null && (n = tab.length) > 0 &&
           (e = tabAt(tab, (n - 1) & h)) != null){
            if((eh = e.hash) == h){
                if((ek = e.key) == key || (ek != null && key.equals(ek)))
                    return e.val;
            }else if(eh < 0)
                return (p = e.find(h, key)) != null ? p.val : null;
            while ((e = e.next) != null) {
                if(e.hash == h &&
                   ((ek = e.key) == key || (ek != null && key.equals(ek))))
                    return e.val;
            }
        }
        return null;
    }

    public boolean containsKey(Object key){
        return get(key) != null;
    }

    public boolean containsValue(Object value){
        if(value == null)
            throw new NullPointerException();
        Node<K, V>[] t;
        if((t = table) != null){
            Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
            for(Node<K, V> p; (p = it.advance()) != null; ){
                V v;
                if((v = p.val) == value || (v != null && value.equals(v)))
                    return true;
            }
        }
        return false;
    }

    public V put(K key, V value){
        return putVal(key, value, false);
    }

    final V putVal(K key, V value, boolean onlyIfAbsent){
        if(key == null || value == null) throw new NullPointerException();
        int hash = spread(key.hashCode());
        int binCount = 0;
        for(Node<K, V>[] tab = table; ; ){
            Node<K, V> f;
            int n, i, fh;
            if(tab == null || (n = tab.length) == 0)
                tab = initTable();
            else if((f = tabAt(tab, i = (n - 1) & hash)) == null){
                if(casTabAt(tab, i, null,
                            new Node<K, V>(hash, key, value, null)))
                    break;                   // no lock when adding to empty bin
            }else if((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else{
                V oldVal = null;
                synchronized (f) {    // 加锁
                    if(tabAt(tab, i) == f){
                        if(fh >= 0){
                            binCount = 1;
                            for(Node<K, V> e = f; ; ++binCount){
                                K ek;
                                if(e.hash == hash &&
                                   ((ek = e.key) == key ||
                                    (ek != null && key.equals(ek)))){
                                    oldVal = e.val;
                                    if(!onlyIfAbsent)
                                        e.val = value;
                                    break;
                                }
                                Node<K, V> pred = e;
                                if((e = e.next) == null){
                                    pred.next = new Node<K, V>(hash, key,
                                                               value, null);
                                    break;
                                }
                            }
                        }else if(f instanceof TreeBin){
                            Node<K, V> p;
                            binCount = 2;
                            if((p = ((TreeBin<K, V>) f).putTreeVal(hash, key,
                                                                   value)) != null){
                                oldVal = p.val;
                                if(!onlyIfAbsent)
                                    p.val = value;
                            }
                        }
                    }
                }
                if(binCount != 0){
                    if(binCount >= TREEIFY_THRESHOLD)
                        treeifyBin(tab, i);
                    if(oldVal != null)
                        return oldVal;
                    break;
                }
            }
        }
        addCount(1L, binCount);
        return null;
    }

    public void putAll(Map<? extends K, ? extends V> m){
        tryPresize(m.size());
        for(Map.Entry<? extends K, ? extends V> e : m.entrySet()){ putVal(e.getKey(), e.getValue(), false); }
    }

    public V remove(Object key){
        return replaceNode(key, null, null);
    }

    final V replaceNode(Object key, V value, Object cv){
        int hash = spread(key.hashCode());
        for(Node<K, V>[] tab = table; ; ){
            Node<K, V> f;
            int n, i, fh;
            if(tab == null || (n = tab.length) == 0 ||
               (f = tabAt(tab, i = (n - 1) & hash)) == null)
                break;
            else if((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else{
                V oldVal = null;
                boolean validated = false;
                synchronized (f) {
                    if(tabAt(tab, i) == f){
                        if(fh >= 0){
                            validated = true;
                            for(Node<K, V> e = f, pred = null; ; ){
                                K ek;
                                if(e.hash == hash &&
                                   ((ek = e.key) == key ||
                                    (ek != null && key.equals(ek)))){
                                    V ev = e.val;
                                    if(cv == null || cv == ev ||
                                       (ev != null && cv.equals(ev))){
                                        oldVal = ev;
                                        if(value != null)
                                            e.val = value;
                                        else if(pred != null)
                                            pred.next = e.next;
                                        else
                                            setTabAt(tab, i, e.next);
                                    }
                                    break;
                                }
                                pred = e;
                                if((e = e.next) == null)
                                    break;
                            }
                        }else if(f instanceof TreeBin){
                            validated = true;
                            TreeBin<K, V> t = (TreeBin<K, V>) f;
                            TreeNode<K, V> r, p;
                            if((r = t.root) != null &&
                               (p = r.findTreeNode(hash, key, null)) != null){
                                V pv = p.val;
                                if(cv == null || cv == pv ||
                                   (pv != null && cv.equals(pv))){
                                    oldVal = pv;
                                    if(value != null)
                                        p.val = value;
                                    else if(t.removeTreeNode(p))
                                        setTabAt(tab, i, untreeify(t.first));
                                }
                            }
                        }
                    }
                }
                if(validated){
                    if(oldVal != null){
                        if(value == null)
                            addCount(-1L, -1);
                        return oldVal;
                    }
                    break;
                }
            }
        }
        return null;
    }

    public void clear(){
        long delta = 0L; // negative number of deletions
        int i = 0;
        Node<K, V>[] tab = table;
        while (tab != null && i < tab.length) {
            int fh;
            Node<K, V> f = tabAt(tab, i);
            if(f == null)
                ++i;
            else if((fh = f.hash) == MOVED){
                tab = helpTransfer(tab, f);
                i = 0; // restart
            }else{
                synchronized (f) {
                    if(tabAt(tab, i) == f){
                        Node<K, V> p = (fh >= 0 ? f :
                                (f instanceof TreeBin) ?
                                        ((TreeBin<K, V>) f).first : null);
                        while (p != null) {
                            --delta;
                            p = p.next;
                        }
                        setTabAt(tab, i++, null);
                    }
                }
            }
        }
        if(delta != 0L)
            addCount(delta, -1);
    }

    public KeySetView<K, V> keySet(){
        KeySetView<K, V> ks;
        return (ks = keySet) != null ? ks : (keySet = new KeySetView<K, V>(this, null));
    }

    public Collection<V> values(){
        ValuesView<K, V> vs;
        return (vs = values) != null ? vs : (values = new ValuesView<K, V>(this));
    }

    public Set<Map.Entry<K, V>> entrySet(){
        EntrySetView<K, V> es;
        return (es = entrySet) != null ? es : (entrySet = new EntrySetView<K, V>(this));
    }

    public int hashCode(){
        int h = 0;
        Node<K, V>[] t;
        if((t = table) != null){
            Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
            for(Node<K, V> p; (p = it.advance()) != null; ){ h += p.key.hashCode() ^ p.val.hashCode(); }
        }
        return h;
    }

    public String toString(){
        Node<K, V>[] t;
        int f = (t = table) == null ? 0 : t.length;
        Traverser<K, V> it = new Traverser<K, V>(t, f, 0, f);
        StringBuilder sb = new StringBuilder();
        sb.append('{');
        Node<K, V> p;
        if((p = it.advance()) != null){
            for(; ; ){
                K k = p.key;
                V v = p.val;
                sb.append(k == this ? "(this Map)" : k);
                sb.append('=');
                sb.append(v == this ? "(this Map)" : v);
                if((p = it.advance()) == null)
                    break;
                sb.append(',').append(' ');
            }
        }
        return sb.append('}').toString();
    }

    public boolean equals(Object o){
        if(o != this){
            if(!(o instanceof Map))
                return false;
            Map<?, ?> m = (Map<?, ?>) o;
            Node<K, V>[] t;
            int f = (t = table) == null ? 0 : t.length;
            Traverser<K, V> it = new Traverser<K, V>(t, f, 0, f);
            for(Node<K, V> p; (p = it.advance()) != null; ){
                V val = p.val;
                Object v = m.get(p.key);
                if(v == null || (v != val && !v.equals(val)))
                    return false;
            }
            for(Map.Entry<?, ?> e : m.entrySet()){
                Object mk, mv, v;
                if((mk = e.getKey()) == null ||
                   (mv = e.getValue()) == null ||
                   (v = get(mk)) == null ||
                   (mv != v && !mv.equals(v)))
                    return false;
            }
        }
        return true;
    }

    // 分段锁
    static class Segment<K, V> extends ReentrantLock implements Serializable {
        private static final long serialVersionUID = 2249069246763182397L;
        final float loadFactor;

        Segment(float lf){ this.loadFactor = lf; }
    }

    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException{
        // For serialization compatibility
        // Emulate segment calculation from previous version of this class
        int sshift = 0;
        int ssize = 1;
        while (ssize < DEFAULT_CONCURRENCY_LEVEL) {
            ++sshift;
            ssize <<= 1;
        }
        int segmentShift = 32 - sshift;
        int segmentMask = ssize - 1;
        @SuppressWarnings("unchecked")
        Segment<K, V>[] segments = (Segment<K, V>[])
                new Segment<?, ?>[DEFAULT_CONCURRENCY_LEVEL];
        for(int i = 0; i < segments.length; ++i){ segments[i] = new Segment<K, V>(LOAD_FACTOR); }
        s.putFields().put("segments", segments);
        s.putFields().put("segmentShift", segmentShift);
        s.putFields().put("segmentMask", segmentMask);
        s.writeFields();

        Node<K, V>[] t;
        if((t = table) != null){
            Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
            for(Node<K, V> p; (p = it.advance()) != null; ){
                s.writeObject(p.key);
                s.writeObject(p.val);
            }
        }
        s.writeObject(null);
        s.writeObject(null);
        segments = null; // throw away
    }

    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException{
        /*
         * To improve performance in typical cases, we create nodes
         * while reading, then place in table once size is known.
         * However, we must also validate uniqueness and deal with
         * overpopulated bins while doing so, which requires
         * specialized versions of putVal mechanics.
         */
        sizeCtl = -1; // force exclusion for table construction
        s.defaultReadObject();
        long size = 0L;
        Node<K, V> p = null;
        for(; ; ){
            @SuppressWarnings("unchecked")
            K k = (K) s.readObject();
            @SuppressWarnings("unchecked")
            V v = (V) s.readObject();
            if(k != null && v != null){
                p = new Node<K, V>(spread(k.hashCode()), k, v, p);
                ++size;
            }else
                break;
        }
        if(size == 0L)
            sizeCtl = 0;
        else{
            int n;
            if(size >= (long) (MAXIMUM_CAPACITY >>> 1))
                n = MAXIMUM_CAPACITY;
            else{
                int sz = (int) size;
                n = tableSizeFor(sz + (sz >>> 1) + 1);
            }
            @SuppressWarnings("unchecked")
            Node<K, V>[] tab = (Node<K, V>[]) new Node<?, ?>[n];
            int mask = n - 1;
            long added = 0L;
            while (p != null) {
                boolean insertAtFront;
                Node<K, V> next = p.next, first;
                int h = p.hash, j = h & mask;
                if((first = tabAt(tab, j)) == null)
                    insertAtFront = true;
                else{
                    K k = p.key;
                    if(first.hash < 0){
                        TreeBin<K, V> t = (TreeBin<K, V>) first;
                        if(t.putTreeVal(h, k, p.val) == null)
                            ++added;
                        insertAtFront = false;
                    }else{
                        int binCount = 0;
                        insertAtFront = true;
                        Node<K, V> q;
                        K qk;
                        for(q = first; q != null; q = q.next){
                            if(q.hash == h &&
                               ((qk = q.key) == k ||
                                (qk != null && k.equals(qk)))){
                                insertAtFront = false;
                                break;
                            }
                            ++binCount;
                        }
                        if(insertAtFront && binCount >= TREEIFY_THRESHOLD){
                            insertAtFront = false;
                            ++added;
                            p.next = first;
                            TreeNode<K, V> hd = null, tl = null;
                            for(q = p; q != null; q = q.next){
                                TreeNode<K, V> t = new TreeNode<K, V>
                                        (q.hash, q.key, q.val, null, null);
                                if((t.prev = tl) == null)
                                    hd = t;
                                else
                                    tl.next = t;
                                tl = t;
                            }
                            setTabAt(tab, j, new TreeBin<K, V>(hd));
                        }
                    }
                }
                if(insertAtFront){
                    ++added;
                    p.next = first;
                    setTabAt(tab, j, p);
                }
                p = next;
            }
            table = tab;
            sizeCtl = n - (n >>> 2);
            baseCount = added;
        }
    }

    // ConcurrentMap methods  并发方法
    public V putIfAbsent(K key, V value){
        return putVal(key, value, true);
    }

    public boolean remove(Object key, Object value){
        if(key == null)
            throw new NullPointerException();
        return value != null && replaceNode(key, null, value) != null;
    }

    public boolean replace(K key, V oldValue, V newValue){
        if(key == null || oldValue == null || newValue == null)
            throw new NullPointerException();
        return replaceNode(key, newValue, oldValue) != null;
    }

    public V replace(K key, V value){
        if(key == null || value == null)
            throw new NullPointerException();
        return replaceNode(key, value, null);
    }

    // Overrides of JDK8+ Map extension method defaults
    public V getOrDefault(Object key, V defaultValue){
        V v;
        return (v = get(key)) == null ? defaultValue : v;
    }

    public void forEach(BiConsumer<? super K, ? super V> action){
        if(action == null) throw new NullPointerException();
        Node<K, V>[] t;
        if((t = table) != null){
            Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
            for(Node<K, V> p; (p = it.advance()) != null; ){
                action.accept(p.key, p.val);
            }
        }
    }

    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function){
        if(function == null) throw new NullPointerException();
        Node<K, V>[] t;
        if((t = table) != null){
            Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
            for(Node<K, V> p; (p = it.advance()) != null; ){
                V oldValue = p.val;
                for(K key = p.key; ; ){
                    V newValue = function.apply(key, oldValue);
                    if(newValue == null)
                        throw new NullPointerException();
                    if(replaceNode(key, newValue, oldValue) != null ||
                       (oldValue = get(key)) == null)
                        break;
                }
            }
        }
    }

    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction){
        if(key == null || mappingFunction == null)
            throw new NullPointerException();
        int h = spread(key.hashCode());
        V val = null;
        int binCount = 0;
        for(Node<K, V>[] tab = table; ; ){
            Node<K, V> f;
            int n, i, fh;
            if(tab == null || (n = tab.length) == 0)
                tab = initTable();
            else if((f = tabAt(tab, i = (n - 1) & h)) == null){
                Node<K, V> r = new ReservationNode<K, V>();
                synchronized (r) {
                    if(casTabAt(tab, i, null, r)){
                        binCount = 1;
                        Node<K, V> node = null;
                        try {
                            if((val = mappingFunction.apply(key)) != null)
                                node = new Node<K, V>(h, key, val, null);
                        } finally {
                            setTabAt(tab, i, node);
                        }
                    }
                }
                if(binCount != 0)
                    break;
            }else if((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else{
                boolean added = false;
                synchronized (f) {
                    if(tabAt(tab, i) == f){
                        if(fh >= 0){
                            binCount = 1;
                            for(Node<K, V> e = f; ; ++binCount){
                                K ek;
                                V ev;
                                if(e.hash == h &&
                                   ((ek = e.key) == key ||
                                    (ek != null && key.equals(ek)))){
                                    val = e.val;
                                    break;
                                }
                                Node<K, V> pred = e;
                                if((e = e.next) == null){
                                    if((val = mappingFunction.apply(key)) != null){
                                        added = true;
                                        pred.next = new Node<K, V>(h, key, val, null);
                                    }
                                    break;
                                }
                            }
                        }else if(f instanceof TreeBin){
                            binCount = 2;
                            TreeBin<K, V> t = (TreeBin<K, V>) f;
                            TreeNode<K, V> r, p;
                            if((r = t.root) != null &&
                               (p = r.findTreeNode(h, key, null)) != null)
                                val = p.val;
                            else if((val = mappingFunction.apply(key)) != null){
                                added = true;
                                t.putTreeVal(h, key, val);
                            }
                        }
                    }
                }
                if(binCount != 0){
                    if(binCount >= TREEIFY_THRESHOLD)
                        treeifyBin(tab, i);
                    if(!added)
                        return val;
                    break;
                }
            }
        }
        if(val != null)
            addCount(1L, binCount);
        return val;
    }

    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction){
        if(key == null || remappingFunction == null)
            throw new NullPointerException();
        int h = spread(key.hashCode());
        V val = null;
        int delta = 0;
        int binCount = 0;
        for(Node<K, V>[] tab = table; ; ){
            Node<K, V> f;
            int n, i, fh;
            if(tab == null || (n = tab.length) == 0)
                tab = initTable();
            else if((f = tabAt(tab, i = (n - 1) & h)) == null)
                break;
            else if((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else{
                synchronized (f) {
                    if(tabAt(tab, i) == f){
                        if(fh >= 0){
                            binCount = 1;
                            for(Node<K, V> e = f, pred = null; ; ++binCount){
                                K ek;
                                if(e.hash == h &&
                                   ((ek = e.key) == key ||
                                    (ek != null && key.equals(ek)))){
                                    val = remappingFunction.apply(key, e.val);
                                    if(val != null)
                                        e.val = val;
                                    else{
                                        delta = -1;
                                        Node<K, V> en = e.next;
                                        if(pred != null)
                                            pred.next = en;
                                        else
                                            setTabAt(tab, i, en);
                                    }
                                    break;
                                }
                                pred = e;
                                if((e = e.next) == null)
                                    break;
                            }
                        }else if(f instanceof TreeBin){
                            binCount = 2;
                            TreeBin<K, V> t = (TreeBin<K, V>) f;
                            TreeNode<K, V> r, p;
                            if((r = t.root) != null &&
                               (p = r.findTreeNode(h, key, null)) != null){
                                val = remappingFunction.apply(key, p.val);
                                if(val != null)
                                    p.val = val;
                                else{
                                    delta = -1;
                                    if(t.removeTreeNode(p))
                                        setTabAt(tab, i, untreeify(t.first));
                                }
                            }
                        }
                    }
                }
                if(binCount != 0)
                    break;
            }
        }
        if(delta != 0)
            addCount((long) delta, binCount);
        return val;
    }

    public V compute(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction){
        if(key == null || remappingFunction == null)
            throw new NullPointerException();
        int h = spread(key.hashCode());
        V val = null;
        int delta = 0;
        int binCount = 0;
        for(Node<K, V>[] tab = table; ; ){
            Node<K, V> f;
            int n, i, fh;
            if(tab == null || (n = tab.length) == 0)
                tab = initTable();
            else if((f = tabAt(tab, i = (n - 1) & h)) == null){
                Node<K, V> r = new ReservationNode<K, V>();
                synchronized (r) {
                    if(casTabAt(tab, i, null, r)){
                        binCount = 1;
                        Node<K, V> node = null;
                        try {
                            if((val = remappingFunction.apply(key, null)) != null){
                                delta = 1;
                                node = new Node<K, V>(h, key, val, null);
                            }
                        } finally {
                            setTabAt(tab, i, node);
                        }
                    }
                }
                if(binCount != 0)
                    break;
            }else if((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else{
                synchronized (f) {
                    if(tabAt(tab, i) == f){
                        if(fh >= 0){
                            binCount = 1;
                            for(Node<K, V> e = f, pred = null; ; ++binCount){
                                K ek;
                                if(e.hash == h &&
                                   ((ek = e.key) == key ||
                                    (ek != null && key.equals(ek)))){
                                    val = remappingFunction.apply(key, e.val);
                                    if(val != null)
                                        e.val = val;
                                    else{
                                        delta = -1;
                                        Node<K, V> en = e.next;
                                        if(pred != null)
                                            pred.next = en;
                                        else
                                            setTabAt(tab, i, en);
                                    }
                                    break;
                                }
                                pred = e;
                                if((e = e.next) == null){
                                    val = remappingFunction.apply(key, null);
                                    if(val != null){
                                        delta = 1;
                                        pred.next =
                                                new Node<K, V>(h, key, val, null);
                                    }
                                    break;
                                }
                            }
                        }else if(f instanceof TreeBin){
                            binCount = 1;
                            TreeBin<K, V> t = (TreeBin<K, V>) f;
                            TreeNode<K, V> r, p;
                            if((r = t.root) != null)
                                p = r.findTreeNode(h, key, null);
                            else
                                p = null;
                            V pv = (p == null) ? null : p.val;
                            val = remappingFunction.apply(key, pv);
                            if(val != null){
                                if(p != null)
                                    p.val = val;
                                else{
                                    delta = 1;
                                    t.putTreeVal(h, key, val);
                                }
                            }else if(p != null){
                                delta = -1;
                                if(t.removeTreeNode(p))
                                    setTabAt(tab, i, untreeify(t.first));
                            }
                        }
                    }
                }
                if(binCount != 0){
                    if(binCount >= TREEIFY_THRESHOLD)
                        treeifyBin(tab, i);
                    break;
                }
            }
        }
        if(delta != 0)
            addCount((long) delta, binCount);
        return val;
    }

    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction){
        if(key == null || value == null || remappingFunction == null)
            throw new NullPointerException();
        int h = spread(key.hashCode());
        V val = null;
        int delta = 0;
        int binCount = 0;
        for(Node<K, V>[] tab = table; ; ){
            Node<K, V> f;
            int n, i, fh;
            if(tab == null || (n = tab.length) == 0)
                tab = initTable();
            else if((f = tabAt(tab, i = (n - 1) & h)) == null){
                if(casTabAt(tab, i, null, new Node<K, V>(h, key, value, null))){
                    delta = 1;
                    val = value;
                    break;
                }
            }else if((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else{
                synchronized (f) {
                    if(tabAt(tab, i) == f){
                        if(fh >= 0){
                            binCount = 1;
                            for(Node<K, V> e = f, pred = null; ; ++binCount){
                                K ek;
                                if(e.hash == h &&
                                   ((ek = e.key) == key ||
                                    (ek != null && key.equals(ek)))){
                                    val = remappingFunction.apply(e.val, value);
                                    if(val != null)
                                        e.val = val;
                                    else{
                                        delta = -1;
                                        Node<K, V> en = e.next;
                                        if(pred != null)
                                            pred.next = en;
                                        else
                                            setTabAt(tab, i, en);
                                    }
                                    break;
                                }
                                pred = e;
                                if((e = e.next) == null){
                                    delta = 1;
                                    val = value;
                                    pred.next =
                                            new Node<K, V>(h, key, val, null);
                                    break;
                                }
                            }
                        }else if(f instanceof TreeBin){
                            binCount = 2;
                            TreeBin<K, V> t = (TreeBin<K, V>) f;
                            TreeNode<K, V> r = t.root;
                            TreeNode<K, V> p = (r == null) ? null :
                                    r.findTreeNode(h, key, null);
                            val = (p == null) ? value :
                                    remappingFunction.apply(p.val, value);
                            if(val != null){
                                if(p != null)
                                    p.val = val;
                                else{
                                    delta = 1;
                                    t.putTreeVal(h, key, val);
                                }
                            }else if(p != null){
                                delta = -1;
                                if(t.removeTreeNode(p))
                                    setTabAt(tab, i, untreeify(t.first));
                            }
                        }
                    }
                }
                if(binCount != 0){
                    if(binCount >= TREEIFY_THRESHOLD)
                        treeifyBin(tab, i);
                    break;
                }
            }
        }
        if(delta != 0)
            addCount((long) delta, binCount);
        return val;
    }

    // Hashtable legacy methods

    public boolean contains(Object value){
        return containsValue(value);
    }

    public Enumeration<K> keys(){
        Node<K, V>[] t;
        int f = (t = table) == null ? 0 : t.length;
        return new KeyIterator<K, V>(t, f, 0, f, this);
    }

    public Enumeration<V> elements(){
        Node<K, V>[] t;
        int f = (t = table) == null ? 0 : t.length;
        return new ValueIterator<K, V>(t, f, 0, f, this);
    }

    // ConcurrentHashMap-only methods

    public long mappingCount(){
        long n = sumCount();
        return (n < 0L) ? 0L : n; // ignore transient negative values
    }

    public static <K> KeySetView<K, Boolean> newKeySet(){
        return new KeySetView<K, Boolean>
                (new ConcurrentHashMap<K, Boolean>(), Boolean.TRUE);
    }

    public static <K> KeySetView<K, Boolean> newKeySet(int initialCapacity){
        return new KeySetView<K, Boolean>
                (new ConcurrentHashMap<K, Boolean>(initialCapacity), Boolean.TRUE);
    }

    public KeySetView<K, V> keySet(V mappedValue){
        if(mappedValue == null)
            throw new NullPointerException();
        return new KeySetView<K, V>(this, mappedValue);
    }

    /* ---------------- Special Nodes -------------- */

    static final class ForwardingNode<K, V> extends Node<K, V> {
        final Node<K, V>[] nextTable;

        ForwardingNode(Node<K, V>[] tab){
            super(MOVED, null, null, null);
            this.nextTable = tab;
        }

        Node<K, V> find(int h, Object k){
            // loop to avoid arbitrarily deep recursion on forwarding nodes
            outer:
            for(Node<K, V>[] tab = nextTable; ; ){
                Node<K, V> e;
                int n;
                if(k == null || tab == null || (n = tab.length) == 0 ||
                   (e = tabAt(tab, (n - 1) & h)) == null)
                    return null;
                for(; ; ){
                    int eh;
                    K ek;
                    if((eh = e.hash) == h &&
                       ((ek = e.key) == k || (ek != null && k.equals(ek))))
                        return e;
                    if(eh < 0){
                        if(e instanceof ForwardingNode){
                            tab = ((ForwardingNode<K, V>) e).nextTable;
                            continue outer;
                        }else
                            return e.find(h, k);
                    }
                    if((e = e.next) == null)
                        return null;
                }
            }
        }
    }
    static final class ReservationNode<K, V> extends Node<K, V> {
        ReservationNode(){
            super(RESERVED, null, null, null);
        }

        Node<K, V> find(int h, Object k){
            return null;
        }
    }
    static final int resizeStamp(int n){
        return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
    }
    private final Node<K, V>[] initTable(){
        Node<K, V>[] tab;
        int sc;
        while ((tab = table) == null || tab.length == 0) {
            if((sc = sizeCtl) < 0)
                Thread.yield(); // lost initialization race; just spin
            else if(U.compareAndSwapInt(this, SIZECTL, sc, -1)){
                try {
                    if((tab = table) == null || tab.length == 0){
                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                        @SuppressWarnings("unchecked")
                        Node<K, V>[] nt = (Node<K, V>[]) new Node<?, ?>[n];
                        table = tab = nt;
                        sc = n - (n >>> 2);
                    }
                } finally {
                    sizeCtl = sc;
                }
                break;
            }
        }
        return tab;
    }
    private final void addCount(long x, int check){
        CounterCell[] as;
        long b, s;
        if((as = counterCells) != null ||
           !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)){
            CounterCell a;
            long v;
            int m;
            boolean uncontended = true;
            if(as == null || (m = as.length - 1) < 0 ||
               (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
               !(uncontended =
                       U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))){
                fullAddCount(x, uncontended);
                return;
            }
            if(check <= 1)
                return;
            s = sumCount();
        }
        if(check >= 0){
            Node<K, V>[] tab, nt;
            int n, sc;
            while (s >= (long) (sc = sizeCtl) && (tab = table) != null &&
                   (n = tab.length) < MAXIMUM_CAPACITY) {
                int rs = resizeStamp(n);
                if(sc < 0){
                    if((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                       sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                       transferIndex <= 0)
                        break;
                    if(U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
                        transfer(tab, nt);
                }else if(U.compareAndSwapInt(this, SIZECTL, sc,
                                             (rs << RESIZE_STAMP_SHIFT) + 2))
                    transfer(tab, null);
                s = sumCount();
            }
        }
    }

    /**
     * Helps transfer if a resize is in progress.
     */
    final Node<K, V>[] helpTransfer(Node<K, V>[] tab, Node<K, V> f){
        Node<K, V>[] nextTab;
        int sc;
        if(tab != null && (f instanceof ForwardingNode) &&
           (nextTab = ((ForwardingNode<K, V>) f).nextTable) != null){
            int rs = resizeStamp(tab.length);
            while (nextTab == nextTable && table == tab &&
                   (sc = sizeCtl) < 0) {
                if((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                   sc == rs + MAX_RESIZERS || transferIndex <= 0)
                    break;
                if(U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)){
                    transfer(tab, nextTab);
                    break;
                }
            }
            return nextTab;
        }
        return table;
    }
    private final void tryPresize(int size){
        int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
                tableSizeFor(size + (size >>> 1) + 1);
        int sc;
        while ((sc = sizeCtl) >= 0) {
            Node<K, V>[] tab = table;
            int n;
            if(tab == null || (n = tab.length) == 0){
                n = (sc > c) ? sc : c;
                if(U.compareAndSwapInt(this, SIZECTL, sc, -1)){
                    try {
                        if(table == tab){
                            @SuppressWarnings("unchecked")
                            Node<K, V>[] nt = (Node<K, V>[]) new Node<?, ?>[n];
                            table = nt;
                            sc = n - (n >>> 2);
                        }
                    } finally {
                        sizeCtl = sc;
                    }
                }
            }else if(c <= sc || n >= MAXIMUM_CAPACITY)
                break;
            else if(tab == table){
                int rs = resizeStamp(n);
                if(sc < 0){
                    Node<K, V>[] nt;
                    if((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                       sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                       transferIndex <= 0)
                        break;
                    if(U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
                        transfer(tab, nt);
                }else if(U.compareAndSwapInt(this, SIZECTL, sc,
                                             (rs << RESIZE_STAMP_SHIFT) + 2))
                    transfer(tab, null);
            }
        }
    }
    private final void transfer(Node<K, V>[] tab, Node<K, V>[] nextTab){
        int n = tab.length, stride;
        if((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
            stride = MIN_TRANSFER_STRIDE; // subdivide range
        if(nextTab == null){            // initiating
            try {
                @SuppressWarnings("unchecked")
                Node<K, V>[] nt = (Node<K, V>[]) new Node<?, ?>[n << 1];
                nextTab = nt;
            } catch (Throwable ex) {      // try to cope with OOME
                sizeCtl = Integer.MAX_VALUE;
                return;
            }
            nextTable = nextTab;
            transferIndex = n;
        }
        int nextn = nextTab.length;
        ForwardingNode<K, V> fwd = new ForwardingNode<K, V>(nextTab);
        boolean advance = true;
        boolean finishing = false; // to ensure sweep before committing nextTab
        for(int i = 0, bound = 0; ; ){
            Node<K, V> f;
            int fh;
            while (advance) {
                int nextIndex, nextBound;
                if(--i >= bound || finishing)
                    advance = false;
                else if((nextIndex = transferIndex) <= 0){
                    i = -1;
                    advance = false;
                }else if(U.compareAndSwapInt
                        (this, TRANSFERINDEX, nextIndex,
                         nextBound = (nextIndex > stride ?
                                 nextIndex - stride : 0))){
                    bound = nextBound;
                    i = nextIndex - 1;
                    advance = false;
                }
            }
            if(i < 0 || i >= n || i + n >= nextn){
                int sc;
                if(finishing){
                    nextTable = null;
                    table = nextTab;
                    sizeCtl = (n << 1) - (n >>> 1);
                    return;
                }
                if(U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)){
                    if((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
                        return;
                    finishing = advance = true;
                    i = n; // recheck before commit
                }
            }else if((f = tabAt(tab, i)) == null)
                advance = casTabAt(tab, i, null, fwd);
            else if((fh = f.hash) == MOVED)
                advance = true; // already processed
            else{
                synchronized (f) {
                    if(tabAt(tab, i) == f){
                        Node<K, V> ln, hn;
                        if(fh >= 0){
                            int runBit = fh & n;
                            Node<K, V> lastRun = f;
                            for(Node<K, V> p = f.next; p != null; p = p.next){
                                int b = p.hash & n;
                                if(b != runBit){
                                    runBit = b;
                                    lastRun = p;
                                }
                            }
                            if(runBit == 0){
                                ln = lastRun;
                                hn = null;
                            }else{
                                hn = lastRun;
                                ln = null;
                            }
                            for(Node<K, V> p = f; p != lastRun; p = p.next){
                                int ph = p.hash;
                                K pk = p.key;
                                V pv = p.val;
                                if((ph & n) == 0)
                                    ln = new Node<K, V>(ph, pk, pv, ln);
                                else
                                    hn = new Node<K, V>(ph, pk, pv, hn);
                            }
                            setTabAt(nextTab, i, ln);
                            setTabAt(nextTab, i + n, hn);
                            setTabAt(tab, i, fwd);
                            advance = true;
                        }else if(f instanceof TreeBin){
                            TreeBin<K, V> t = (TreeBin<K, V>) f;
                            TreeNode<K, V> lo = null, loTail = null;
                            TreeNode<K, V> hi = null, hiTail = null;
                            int lc = 0, hc = 0;
                            for(Node<K, V> e = t.first; e != null; e = e.next){
                                int h = e.hash;
                                TreeNode<K, V> p = new TreeNode<K, V>
                                        (h, e.key, e.val, null, null);
                                if((h & n) == 0){
                                    if((p.prev = loTail) == null)
                                        lo = p;
                                    else
                                        loTail.next = p;
                                    loTail = p;
                                    ++lc;
                                }else{
                                    if((p.prev = hiTail) == null)
                                        hi = p;
                                    else
                                        hiTail.next = p;
                                    hiTail = p;
                                    ++hc;
                                }
                            }
                            ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
                                    (hc != 0) ? new TreeBin<K, V>(lo) : t;
                            hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
                                    (lc != 0) ? new TreeBin<K, V>(hi) : t;
                            setTabAt(nextTab, i, ln);
                            setTabAt(nextTab, i + n, hn);
                            setTabAt(tab, i, fwd);
                            advance = true;
                        }
                    }
                }
            }
        }
    }
    @sun.misc.Contended
    static final class CounterCell {
        volatile long value;

        CounterCell(long x){ value = x; }
    }

    final long sumCount(){
        CounterCell[] as = counterCells;
        CounterCell a;
        long sum = baseCount;
        if(as != null){
            for(int i = 0; i < as.length; ++i){
                if((a = as[i]) != null)
                    sum += a.value;
            }
        }
        return sum;
    }

    // See LongAdder version for explanation
    private final void fullAddCount(long x, boolean wasUncontended){
        int h;
        if((h = ThreadLocalRandom.getProbe()) == 0){
            ThreadLocalRandom.localInit();      // force initialization
            h = ThreadLocalRandom.getProbe();
            wasUncontended = true;
        }
        boolean collide = false;                // True if last slot nonempty
        for(; ; ){
            CounterCell[] as;
            CounterCell a;
            int n;
            long v;
            if((as = counterCells) != null && (n = as.length) > 0){
                if((a = as[(n - 1) & h]) == null){
                    if(cellsBusy == 0){            // Try to attach new Cell
                        CounterCell r = new CounterCell(x); // Optimistic create
                        if(cellsBusy == 0 &&
                           U.compareAndSwapInt(this, CELLSBUSY, 0, 1)){
                            boolean created = false;
                            try {               // Recheck under lock
                                CounterCell[] rs;
                                int m, j;
                                if((rs = counterCells) != null &&
                                   (m = rs.length) > 0 &&
                                   rs[j = (m - 1) & h] == null){
                                    rs[j] = r;
                                    created = true;
                                }
                            } finally {
                                cellsBusy = 0;
                            }
                            if(created)
                                break;
                            continue;           // Slot is now non-empty
                        }
                    }
                    collide = false;
                }else if(!wasUncontended)       // CAS already known to fail
                    wasUncontended = true;      // Continue after rehash
                else if(U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
                    break;
                else if(counterCells != as || n >= NCPU)
                    collide = false;            // At max size or stale
                else if(!collide)
                    collide = true;
                else if(cellsBusy == 0 &&
                        U.compareAndSwapInt(this, CELLSBUSY, 0, 1)){
                    try {
                        if(counterCells == as){// Expand table unless stale
                            CounterCell[] rs = new CounterCell[n << 1];
                            for(int i = 0; i < n; ++i){ rs[i] = as[i]; }
                            counterCells = rs;
                        }
                    } finally {
                        cellsBusy = 0;
                    }
                    collide = false;
                    continue;                   // Retry with expanded table
                }
                h = ThreadLocalRandom.advanceProbe(h);
            }else if(cellsBusy == 0 && counterCells == as &&
                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)){
                boolean init = false;
                try {                           // Initialize table
                    if(counterCells == as){
                        CounterCell[] rs = new CounterCell[2];
                        rs[h & 1] = new CounterCell(x);
                        counterCells = rs;
                        init = true;
                    }
                } finally {
                    cellsBusy = 0;
                }
                if(init)
                    break;
            }else if(U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
                break;                          // Fall back on using base
        }
    }

    private final void treeifyBin(Node<K, V>[] tab, int index){
        Node<K, V> b;
        int n, sc;
        if(tab != null){
            if((n = tab.length) < MIN_TREEIFY_CAPACITY)
                tryPresize(n << 1);
            else if((b = tabAt(tab, index)) != null && b.hash >= 0){
                synchronized (b) {
                    if(tabAt(tab, index) == b){
                        TreeNode<K, V> hd = null, tl = null;
                        for(Node<K, V> e = b; e != null; e = e.next){
                            TreeNode<K, V> p =
                                    new TreeNode<K, V>(e.hash, e.key, e.val,
                                                       null, null);
                            if((p.prev = tl) == null)
                                hd = p;
                            else
                                tl.next = p;
                            tl = p;
                        }
                        setTabAt(tab, index, new TreeBin<K, V>(hd));
                    }
                }
            }
        }
    }

    static <K, V> Node<K, V> untreeify(Node<K, V> b){
        Node<K, V> hd = null, tl = null;
        for(Node<K, V> q = b; q != null; q = q.next){
            Node<K, V> p = new Node<K, V>(q.hash, q.key, q.val, null);
            if(tl == null)
                hd = p;
            else
                tl.next = p;
            tl = p;
        }
        return hd;
    }

    //红黑树
    static final class TreeNode<K, V> extends Node<K, V> {
        TreeNode<K, V> parent;  // red-black tree links
        TreeNode<K, V> left;
        TreeNode<K, V> right;
        TreeNode<K, V> prev;    // needed to unlink next upon deletion
        boolean red;

        TreeNode(int hash, K key, V val, Node<K, V> next,
                TreeNode<K, V> parent){
            super(hash, key, val, next);
            this.parent = parent;
        }

        Node<K, V> find(int h, Object k){
            return findTreeNode(h, k, null);
        }

        /**
         * Returns the TreeNode (or null if not found) for the given key
         * starting at given root.
         */
        final TreeNode<K, V> findTreeNode(int h, Object k, Class<?> kc){
            if(k != null){
                TreeNode<K, V> p = this;
                do {
                    int ph, dir;
                    K pk;
                    TreeNode<K, V> q;
                    TreeNode<K, V> pl = p.left, pr = p.right;
                    if((ph = p.hash) > h)
                        p = pl;
                    else if(ph < h)
                        p = pr;
                    else if((pk = p.key) == k || (pk != null && k.equals(pk)))
                        return p;
                    else if(pl == null)
                        p = pr;
                    else if(pr == null)
                        p = pl;
                    else if((kc != null ||
                             (kc = comparableClassFor(k)) != null) &&
                            (dir = compareComparables(kc, k, pk)) != 0)
                        p = (dir < 0) ? pl : pr;
                    else if((q = pr.findTreeNode(h, k, kc)) != null)
                        return q;
                    else
                        p = pl;
                } while (p != null);
            }
            return null;
        }
    }

    /* ---------------- TreeBins -------------- */

    //封装Node,加锁的红黑树
    static final class TreeBin<K, V> extends Node<K, V> {
        TreeNode<K, V> root;
        volatile TreeNode<K, V> first;
        volatile Thread waiter;
        volatile int lockState;
        // values for lockState
        static final int WRITER = 1; // set while holding write lock
        static final int WAITER = 2; // set when waiting for write lock
        static final int READER = 4; // increment value for setting read lock

        /**
         * Tie-breaking utility for ordering insertions when equal
         * hashCodes and non-comparable. We don't require a total
         * order, just a consistent insertion rule to maintain
         * equivalence across rebalancings. Tie-breaking further than
         * necessary simplifies testing a bit.
         */
        static int tieBreakOrder(Object a, Object b){
            int d;
            if(a == null || b == null ||
               (d = a.getClass().getName().
                       compareTo(b.getClass().getName())) == 0)
                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
                        -1 : 1);
            return d;
        }

        /**
         * Creates bin with initial set of nodes headed by b.
         */
        TreeBin(TreeNode<K, V> b){
            super(TREEBIN, null, null, null);
            this.first = b;
            TreeNode<K, V> r = null;
            for(TreeNode<K, V> x = b, next; x != null; x = next){
                next = (TreeNode<K, V>) x.next;
                x.left = x.right = null;
                if(r == null){
                    x.parent = null;
                    x.red = false;
                    r = x;
                }else{
                    K k = x.key;
                    int h = x.hash;
                    Class<?> kc = null;
                    for(TreeNode<K, V> p = r; ; ){
                        int dir, ph;
                        K pk = p.key;
                        if((ph = p.hash) > h)
                            dir = -1;
                        else if(ph < h)
                            dir = 1;
                        else if((kc == null &&
                                 (kc = comparableClassFor(k)) == null) ||
                                (dir = compareComparables(kc, k, pk)) == 0)
                            dir = tieBreakOrder(k, pk);
                        TreeNode<K, V> xp = p;
                        if((p = (dir <= 0) ? p.left : p.right) == null){
                            x.parent = xp;
                            if(dir <= 0)
                                xp.left = x;
                            else
                                xp.right = x;
                            r = balanceInsertion(r, x);
                            break;
                        }
                    }
                }
            }
            this.root = r;
            assert checkInvariants(root);
        }

        /**
         * Acquires write lock for tree restructuring.
         */
        private final void lockRoot(){
            if(!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
                contendedLock(); // offload to separate method
        }

        /**
         * Releases write lock for tree restructuring.
         */
        private final void unlockRoot(){
            lockState = 0;
        }

        /**
         * Possibly blocks awaiting root lock.
         */
        private final void contendedLock(){
            boolean waiting = false;
            for(int s; ; ){
                if(((s = lockState) & ~WAITER) == 0){
                    if(U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)){
                        if(waiting)
                            waiter = null;
                        return;
                    }
                }else if((s & WAITER) == 0){
                    if(U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)){
                        waiting = true;
                        waiter = Thread.currentThread();
                    }
                }else if(waiting)
                    LockSupport.park(this);
            }
        }

        /**
         * Returns matching node or null if none. Tries to search
         * using tree comparisons from root, but continues linear
         * search when lock not available.
         */
        final Node<K, V> find(int h, Object k){
            if(k != null){
                for(Node<K, V> e = first; e != null; ){
                    int s;
                    K ek;
                    if(((s = lockState) & (WAITER | WRITER)) != 0){
                        if(e.hash == h &&
                           ((ek = e.key) == k || (ek != null && k.equals(ek))))
                            return e;
                        e = e.next;
                    }else if(U.compareAndSwapInt(this, LOCKSTATE, s,
                                                 s + READER)){
                        TreeNode<K, V> r, p;
                        try {
                            p = ((r = root) == null ? null :
                                    r.findTreeNode(h, k, null));
                        } finally {
                            Thread w;
                            if(U.getAndAddInt(this, LOCKSTATE, -READER) ==
                               (READER | WAITER) && (w = waiter) != null)
                                LockSupport.unpark(w);
                        }
                        return p;
                    }
                }
            }
            return null;
        }

        /**
         * Finds or adds a node.
         *
         * @return null if added
         */
        final TreeNode<K, V> putTreeVal(int h, K k, V v){
            Class<?> kc = null;
            boolean searched = false;
            for(TreeNode<K, V> p = root; ; ){
                int dir, ph;
                K pk;
                if(p == null){
                    first = root = new TreeNode<K, V>(h, k, v, null, null);
                    break;
                }else if((ph = p.hash) > h)
                    dir = -1;
                else if(ph < h)
                    dir = 1;
                else if((pk = p.key) == k || (pk != null && k.equals(pk)))
                    return p;
                else if((kc == null &&
                         (kc = comparableClassFor(k)) == null) ||
                        (dir = compareComparables(kc, k, pk)) == 0){
                    if(!searched){
                        TreeNode<K, V> q, ch;
                        searched = true;
                        if(((ch = p.left) != null &&
                            (q = ch.findTreeNode(h, k, kc)) != null) ||
                           ((ch = p.right) != null &&
                            (q = ch.findTreeNode(h, k, kc)) != null))
                            return q;
                    }
                    dir = tieBreakOrder(k, pk);
                }

                TreeNode<K, V> xp = p;
                if((p = (dir <= 0) ? p.left : p.right) == null){
                    TreeNode<K, V> x, f = first;
                    first = x = new TreeNode<K, V>(h, k, v, f, xp);
                    if(f != null)
                        f.prev = x;
                    if(dir <= 0)
                        xp.left = x;
                    else
                        xp.right = x;
                    if(!xp.red)
                        x.red = true;
                    else{
                        lockRoot();
                        try {
                            root = balanceInsertion(root, x);
                        } finally {
                            unlockRoot();
                        }
                    }
                    break;
                }
            }
            assert checkInvariants(root);
            return null;
        }

        /**
         * Removes the given node, that must be present before this
         * call.  This is messier than typical red-black deletion code
         * because we cannot swap the contents of an interior node
         * with a leaf successor that is pinned by "next" pointers
         * that are accessible independently of lock. So instead we
         * swap the tree linkages.
         *
         * @return true if now too small, so should be untreeified
         */
        final boolean removeTreeNode(TreeNode<K, V> p){
            TreeNode<K, V> next = (TreeNode<K, V>) p.next;
            TreeNode<K, V> pred = p.prev;  // unlink traversal pointers
            TreeNode<K, V> r, rl;
            if(pred == null)
                first = next;
            else
                pred.next = next;
            if(next != null)
                next.prev = pred;
            if(first == null){
                root = null;
                return true;
            }
            if((r = root) == null || r.right == null || // too small
               (rl = r.left) == null || rl.left == null)
                return true;
            lockRoot();
            try {
                TreeNode<K, V> replacement;
                TreeNode<K, V> pl = p.left;
                TreeNode<K, V> pr = p.right;
                if(pl != null && pr != null){
                    TreeNode<K, V> s = pr, sl;
                    while ((sl = s.left) != null) // find successor
                        s = sl;
                    boolean c = s.red;
                    s.red = p.red;
                    p.red = c; // swap colors
                    TreeNode<K, V> sr = s.right;
                    TreeNode<K, V> pp = p.parent;
                    if(s == pr){ // p was s's direct parent
                        p.parent = s;
                        s.right = p;
                    }else{
                        TreeNode<K, V> sp = s.parent;
                        if((p.parent = sp) != null){
                            if(s == sp.left)
                                sp.left = p;
                            else
                                sp.right = p;
                        }
                        if((s.right = pr) != null)
                            pr.parent = s;
                    }
                    p.left = null;
                    if((p.right = sr) != null)
                        sr.parent = p;
                    if((s.left = pl) != null)
                        pl.parent = s;
                    if((s.parent = pp) == null)
                        r = s;
                    else if(p == pp.left)
                        pp.left = s;
                    else
                        pp.right = s;
                    if(sr != null)
                        replacement = sr;
                    else
                        replacement = p;
                }else if(pl != null)
                    replacement = pl;
                else if(pr != null)
                    replacement = pr;
                else
                    replacement = p;
                if(replacement != p){
                    TreeNode<K, V> pp = replacement.parent = p.parent;
                    if(pp == null)
                        r = replacement;
                    else if(p == pp.left)
                        pp.left = replacement;
                    else
                        pp.right = replacement;
                    p.left = p.right = p.parent = null;
                }

                root = (p.red) ? r : balanceDeletion(r, replacement);

                if(p == replacement){  // detach pointers
                    TreeNode<K, V> pp;
                    if((pp = p.parent) != null){
                        if(p == pp.left)
                            pp.left = null;
                        else if(p == pp.right)
                            pp.right = null;
                        p.parent = null;
                    }
                }
            } finally {
                unlockRoot();
            }
            assert checkInvariants(root);
            return false;
        }

        /* ------------------------------------------------------------ */
        // Red-black tree methods, all adapted from CLR

        static <K, V> TreeNode<K, V> rotateLeft(TreeNode<K, V> root,
                TreeNode<K, V> p){
            TreeNode<K, V> r, pp, rl;
            if(p != null && (r = p.right) != null){
                if((rl = p.right = r.left) != null)
                    rl.parent = p;
                if((pp = r.parent = p.parent) == null)
                    (root = r).red = false;
                else if(pp.left == p)
                    pp.left = r;
                else
                    pp.right = r;
                r.left = p;
                p.parent = r;
            }
            return root;
        }

        static <K, V> TreeNode<K, V> rotateRight(TreeNode<K, V> root,
                TreeNode<K, V> p){
            TreeNode<K, V> l, pp, lr;
            if(p != null && (l = p.left) != null){
                if((lr = p.left = l.right) != null)
                    lr.parent = p;
                if((pp = l.parent = p.parent) == null)
                    (root = l).red = false;
                else if(pp.right == p)
                    pp.right = l;
                else
                    pp.left = l;
                l.right = p;
                p.parent = l;
            }
            return root;
        }

        static <K, V> TreeNode<K, V> balanceInsertion(TreeNode<K, V> root,
                TreeNode<K, V> x){
            x.red = true;
            for(TreeNode<K, V> xp, xpp, xppl, xppr; ; ){
                if((xp = x.parent) == null){
                    x.red = false;
                    return x;
                }else if(!xp.red || (xpp = xp.parent) == null)
                    return root;
                if(xp == (xppl = xpp.left)){
                    if((xppr = xpp.right) != null && xppr.red){
                        xppr.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }else{
                        if(x == xp.right){
                            root = rotateLeft(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if(xp != null){
                            xp.red = false;
                            if(xpp != null){
                                xpp.red = true;
                                root = rotateRight(root, xpp);
                            }
                        }
                    }
                }else{
                    if(xppl != null && xppl.red){
                        xppl.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }else{
                        if(x == xp.left){
                            root = rotateRight(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if(xp != null){
                            xp.red = false;
                            if(xpp != null){
                                xpp.red = true;
                                root = rotateLeft(root, xpp);
                            }
                        }
                    }
                }
            }
        }

        static <K, V> TreeNode<K, V> balanceDeletion(TreeNode<K, V> root,
                TreeNode<K, V> x){
            for(TreeNode<K, V> xp, xpl, xpr; ; ){
                if(x == null || x == root)
                    return root;
                else if((xp = x.parent) == null){
                    x.red = false;
                    return x;
                }else if(x.red){
                    x.red = false;
                    return root;
                }else if((xpl = xp.left) == x){
                    if((xpr = xp.right) != null && xpr.red){
                        xpr.red = false;
                        xp.red = true;
                        root = rotateLeft(root, xp);
                        xpr = (xp = x.parent) == null ? null : xp.right;
                    }
                    if(xpr == null)
                        x = xp;
                    else{
                        TreeNode<K, V> sl = xpr.left, sr = xpr.right;
                        if((sr == null || !sr.red) &&
                           (sl == null || !sl.red)){
                            xpr.red = true;
                            x = xp;
                        }else{
                            if(sr == null || !sr.red){
                                if(sl != null)
                                    sl.red = false;
                                xpr.red = true;
                                root = rotateRight(root, xpr);
                                xpr = (xp = x.parent) == null ?
                                        null : xp.right;
                            }
                            if(xpr != null){
                                xpr.red = (xp == null) ? false : xp.red;
                                if((sr = xpr.right) != null)
                                    sr.red = false;
                            }
                            if(xp != null){
                                xp.red = false;
                                root = rotateLeft(root, xp);
                            }
                            x = root;
                        }
                    }
                }else{ // symmetric
                    if(xpl != null && xpl.red){
                        xpl.red = false;
                        xp.red = true;
                        root = rotateRight(root, xp);
                        xpl = (xp = x.parent) == null ? null : xp.left;
                    }
                    if(xpl == null)
                        x = xp;
                    else{
                        TreeNode<K, V> sl = xpl.left, sr = xpl.right;
                        if((sl == null || !sl.red) &&
                           (sr == null || !sr.red)){
                            xpl.red = true;
                            x = xp;
                        }else{
                            if(sl == null || !sl.red){
                                if(sr != null)
                                    sr.red = false;
                                xpl.red = true;
                                root = rotateLeft(root, xpl);
                                xpl = (xp = x.parent) == null ?
                                        null : xp.left;
                            }
                            if(xpl != null){
                                xpl.red = (xp == null) ? false : xp.red;
                                if((sl = xpl.left) != null)
                                    sl.red = false;
                            }
                            if(xp != null){
                                xp.red = false;
                                root = rotateRight(root, xp);
                            }
                            x = root;
                        }
                    }
                }
            }
        }

        /**
         * Recursive invariant check
         */
        static <K, V> boolean checkInvariants(TreeNode<K, V> t){
            TreeNode<K, V> tp = t.parent, tl = t.left, tr = t.right,
                    tb = t.prev, tn = (TreeNode<K, V>) t.next;
            if(tb != null && tb.next != t)
                return false;
            if(tn != null && tn.prev != t)
                return false;
            if(tp != null && t != tp.left && t != tp.right)
                return false;
            if(tl != null && (tl.parent != t || tl.hash > t.hash))
                return false;
            if(tr != null && (tr.parent != t || tr.hash < t.hash))
                return false;
            if(t.red && tl != null && tl.red && tr != null && tr.red)
                return false;
            if(tl != null && !checkInvariants(tl))
                return false;
            if(tr != null && !checkInvariants(tr))
                return false;
            return true;
        }

        private static final sun.misc.Unsafe U;
        private static final long LOCKSTATE;

        static{
            try {
                U = sun.misc.Unsafe.getUnsafe();
                Class<?> k = TreeBin.class;
                LOCKSTATE = U.objectFieldOffset
                        (k.getDeclaredField("lockState"));
            } catch (Exception e) {
                throw new Error(e);
            }
        }
    }

    /* ----------------Table Traversal -------------- */
    static final class TableStack<K, V> {
        int length;
        int index;
        Node<K, V>[] tab;
        TableStack<K, V> next;
    }

    static class Traverser<K, V> {
        Node<K, V>[] tab;        // current table; updated if resized
        Node<K, V> next;         // the next entry to use
        TableStack<K, V> stack, spare; // to save/restore on ForwardingNodes
        int index;              // index of bin to use next
        int baseIndex;          // current index of initial table
        int baseLimit;          // index bound for initial table
        final int baseSize;     // initial table size

        Traverser(Node<K, V>[] tab, int size, int index, int limit){
            this.tab = tab;
            this.baseSize = size;
            this.baseIndex = this.index = index;
            this.baseLimit = limit;
            this.next = null;
        }

        final Node<K, V> advance(){
            Node<K, V> e;
            if((e = next) != null)
                e = e.next;
            for(; ; ){
                Node<K, V>[] t;
                int i, n;  // must use locals in checks
                if(e != null)
                    return next = e;
                if(baseIndex >= baseLimit || (t = tab) == null ||
                   (n = t.length) <= (i = index) || i < 0)
                    return next = null;
                if((e = tabAt(t, i)) != null && e.hash < 0){
                    if(e instanceof ForwardingNode){
                        tab = ((ForwardingNode<K, V>) e).nextTable;
                        e = null;
                        pushState(t, i, n);
                        continue;
                    }else if(e instanceof TreeBin)
                        e = ((TreeBin<K, V>) e).first;
                    else
                        e = null;
                }
                if(stack != null)
                    recoverState(n);
                else if((index = i + baseSize) >= n)
                    index = ++baseIndex; // visit upper slots if present
            }
        }

        private void pushState(Node<K, V>[] t, int i, int n){
            TableStack<K, V> s = spare;  // reuse if possible
            if(s != null)
                spare = s.next;
            else
                s = new TableStack<K, V>();
            s.tab = t;
            s.length = n;
            s.index = i;
            s.next = stack;
            stack = s;
        }

        private void recoverState(int n){
            TableStack<K, V> s;
            int len;
            while ((s = stack) != null && (index += (len = s.length)) >= n) {
                n = len;
                index = s.index;
                tab = s.tab;
                s.tab = null;
                TableStack<K, V> next = s.next;
                s.next = spare; // save for reuse
                stack = next;
                spare = s;
            }
            if(s == null && (index += baseSize) >= n)
                index = ++baseIndex;
        }
    }

    // 迭代器**********************************************************//
    static class BaseIterator<K, V> extends Traverser<K, V> {
        final ConcurrentHashMap<K, V> map;
        Node<K, V> lastReturned;

        BaseIterator(Node<K, V>[] tab, int size, int index, int limit,
                ConcurrentHashMap<K, V> map){
            super(tab, size, index, limit);
            this.map = map;
            advance();
        }

        public final boolean hasNext(){ return next != null; }

        public final boolean hasMoreElements(){ return next != null; }

        public final void remove(){
            Node<K, V> p;
            if((p = lastReturned) == null)
                throw new IllegalStateException();
            lastReturned = null;
            map.replaceNode(p.key, null, null);
        }
    }

    static final class KeyIterator<K, V> extends BaseIterator<K, V>
            implements Iterator<K>, Enumeration<K> {
        KeyIterator(Node<K, V>[] tab, int index, int size, int limit,
                ConcurrentHashMap<K, V> map){
            super(tab, index, size, limit, map);
        }

        public final K next(){
            Node<K, V> p;
            if((p = next) == null)
                throw new NoSuchElementException();
            K k = p.key;
            lastReturned = p;
            advance();
            return k;
        }

        public final K nextElement(){ return next(); }
    }

    static final class ValueIterator<K, V> extends BaseIterator<K, V>
            implements Iterator<V>, Enumeration<V> {
        ValueIterator(Node<K, V>[] tab, int index, int size, int limit,
                ConcurrentHashMap<K, V> map){
            super(tab, index, size, limit, map);
        }

        public final V next(){
            Node<K, V> p;
            if((p = next) == null)
                throw new NoSuchElementException();
            V v = p.val;
            lastReturned = p;
            advance();
            return v;
        }

        public final V nextElement(){ return next(); }
    }

    static final class EntryIterator<K, V> extends BaseIterator<K, V>
            implements Iterator<Map.Entry<K, V>> {
        EntryIterator(Node<K, V>[] tab, int index, int size, int limit,
                ConcurrentHashMap<K, V> map){
            super(tab, index, size, limit, map);
        }

        public final Map.Entry<K, V> next(){
            Node<K, V> p;
            if((p = next) == null)
                throw new NoSuchElementException();
            K k = p.key;
            V v = p.val;
            lastReturned = p;
            advance();
            return new MapEntry<K, V>(k, v, map);
        }
    }

    static final class MapEntry<K, V> implements Map.Entry<K, V> {
        final K key; // non-null
        V val;       // non-null
        final ConcurrentHashMap<K, V> map;

        MapEntry(K key, V val, ConcurrentHashMap<K, V> map){
            this.key = key;
            this.val = val;
            this.map = map;
        }

        public K getKey(){ return key; }

        public V getValue(){ return val; }

        public int hashCode(){ return key.hashCode() ^ val.hashCode(); }

        public String toString(){ return key + "=" + val; }

        public boolean equals(Object o){
            Object k, v;
            Map.Entry<?, ?> e;
            return ((o instanceof Map.Entry) &&
                    (k = (e = (Map.Entry<?, ?>) o).getKey()) != null &&
                    (v = e.getValue()) != null &&
                    (k == key || k.equals(key)) &&
                    (v == val || v.equals(val)));
        }

        /**
         * Sets our entry's value and writes through to the map. The
         * value to return is somewhat arbitrary here. Since we do not
         * necessarily track asynchronous changes, the most recent
         * "previous" value could be different from what we return (or
         * could even have been removed, in which case the put will
         * re-establish). We do not and cannot guarantee more.
         */
        public V setValue(V value){
            if(value == null) throw new NullPointerException();
            V v = val;
            val = value;
            map.put(key, value);
            return v;
        }
    }

    static final class KeySpliterator<K, V> extends Traverser<K, V>
            implements Spliterator<K> {
        long est;               // size estimate

        KeySpliterator(Node<K, V>[] tab, int size, int index, int limit,
                long est){
            super(tab, size, index, limit);
            this.est = est;
        }

        public Spliterator<K> trySplit(){
            int i, f, h;
            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
                    new KeySpliterator<K, V>(tab, baseSize, baseLimit = h,
                                             f, est >>>= 1);
        }

        public void forEachRemaining(Consumer<? super K> action){
            if(action == null) throw new NullPointerException();
            for(Node<K, V> p; (p = advance()) != null; ){ action.accept(p.key); }
        }

        public boolean tryAdvance(Consumer<? super K> action){
            if(action == null) throw new NullPointerException();
            Node<K, V> p;
            if((p = advance()) == null)
                return false;
            action.accept(p.key);
            return true;
        }

        public long estimateSize(){ return est; }

        public int characteristics(){
            return Spliterator.DISTINCT | Spliterator.CONCURRENT |
                   Spliterator.NONNULL;
        }
    }

    static final class ValueSpliterator<K, V> extends Traverser<K, V>
            implements Spliterator<V> {
        long est;               // size estimate

        ValueSpliterator(Node<K, V>[] tab, int size, int index, int limit,
                long est){
            super(tab, size, index, limit);
            this.est = est;
        }

        public Spliterator<V> trySplit(){
            int i, f, h;
            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
                    new ValueSpliterator<K, V>(tab, baseSize, baseLimit = h,
                                               f, est >>>= 1);
        }

        public void forEachRemaining(Consumer<? super V> action){
            if(action == null) throw new NullPointerException();
            for(Node<K, V> p; (p = advance()) != null; ){ action.accept(p.val); }
        }

        public boolean tryAdvance(Consumer<? super V> action){
            if(action == null) throw new NullPointerException();
            Node<K, V> p;
            if((p = advance()) == null)
                return false;
            action.accept(p.val);
            return true;
        }

        public long estimateSize(){ return est; }

        public int characteristics(){
            return Spliterator.CONCURRENT | Spliterator.NONNULL;
        }
    }

    static final class EntrySpliterator<K, V> extends Traverser<K, V>
            implements Spliterator<Map.Entry<K, V>> {
        final ConcurrentHashMap<K, V> map; // To export MapEntry
        long est;               // size estimate

        EntrySpliterator(Node<K, V>[] tab, int size, int index, int limit,
                long est, ConcurrentHashMap<K, V> map){
            super(tab, size, index, limit);
            this.map = map;
            this.est = est;
        }

        public Spliterator<Map.Entry<K, V>> trySplit(){
            int i, f, h;
            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
                    new EntrySpliterator<K, V>(tab, baseSize, baseLimit = h,
                                               f, est >>>= 1, map);
        }

        public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action){
            if(action == null) throw new NullPointerException();
            for(Node<K, V> p; (p = advance()) != null; ){ action.accept(new MapEntry<K, V>(p.key, p.val, map)); }
        }

        public boolean tryAdvance(Consumer<? super Map.Entry<K, V>> action){
            if(action == null) throw new NullPointerException();
            Node<K, V> p;
            if((p = advance()) == null)
                return false;
            action.accept(new MapEntry<K, V>(p.key, p.val, map));
            return true;
        }

        public long estimateSize(){ return est; }

        public int characteristics(){
            return Spliterator.DISTINCT | Spliterator.CONCURRENT |
                   Spliterator.NONNULL;
        }
    }

    // Parallel bulk operations,并发操作
    final int batchFor(long b){
        long n;
        if(b == Long.MAX_VALUE || (n = sumCount()) <= 1L || n < b)
            return 0;
        int sp = ForkJoinPool.getCommonPoolParallelism() << 2; // slack of 4
        return (b <= 0L || (n /= b) >= sp) ? sp : (int) n;
    }

    public void forEach(long parallelismThreshold,
            BiConsumer<? super K, ? super V> action){
        if(action == null) throw new NullPointerException();
        new ForEachMappingTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 action).invoke();
    }

    public <U> void forEach(long parallelismThreshold,
            BiFunction<? super K, ? super V, ? extends U> transformer,
            Consumer<? super U> action){
        if(transformer == null || action == null)
            throw new NullPointerException();
        new ForEachTransformedMappingTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 transformer, action).invoke();
    }

    public <U> U search(long parallelismThreshold,
            BiFunction<? super K, ? super V, ? extends U> searchFunction){
        if(searchFunction == null) throw new NullPointerException();
        return new SearchMappingsTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 searchFunction, new AtomicReference<U>()).invoke();
    }

    public <U> U reduce(long parallelismThreshold,
            BiFunction<? super K, ? super V, ? extends U> transformer,
            BiFunction<? super U, ? super U, ? extends U> reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceMappingsTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, reducer).invoke();
    }

    public double reduceToDouble(long parallelismThreshold,
            ToDoubleBiFunction<? super K, ? super V> transformer,
            double basis,
            DoubleBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceMappingsToDoubleTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    public long reduceToLong(long parallelismThreshold,
            ToLongBiFunction<? super K, ? super V> transformer,
            long basis,
            LongBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceMappingsToLongTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    public int reduceToInt(long parallelismThreshold,
            ToIntBiFunction<? super K, ? super V> transformer,
            int basis,
            IntBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceMappingsToIntTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    public void forEachKey(long parallelismThreshold,
            Consumer<? super K> action){
        if(action == null) throw new NullPointerException();
        new ForEachKeyTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 action).invoke();
    }

    public <U> void forEachKey(long parallelismThreshold,
            Function<? super K, ? extends U> transformer,
            Consumer<? super U> action){
        if(transformer == null || action == null)
            throw new NullPointerException();
        new ForEachTransformedKeyTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 transformer, action).invoke();
    }

    public <U> U searchKeys(long parallelismThreshold,
            Function<? super K, ? extends U> searchFunction){
        if(searchFunction == null) throw new NullPointerException();
        return new SearchKeysTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 searchFunction, new AtomicReference<U>()).invoke();
    }

    public K reduceKeys(long parallelismThreshold,
            BiFunction<? super K, ? super K, ? extends K> reducer){
        if(reducer == null) throw new NullPointerException();
        return new ReduceKeysTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, reducer).invoke();
    }

    public <U> U reduceKeys(long parallelismThreshold,
            Function<? super K, ? extends U> transformer,
            BiFunction<? super U, ? super U, ? extends U> reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceKeysTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, reducer).invoke();
    }

    public double reduceKeysToDouble(long parallelismThreshold,
            ToDoubleFunction<? super K> transformer,
            double basis,
            DoubleBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceKeysToDoubleTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    public long reduceKeysToLong(long parallelismThreshold,
            ToLongFunction<? super K> transformer,
            long basis,
            LongBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceKeysToLongTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    public int reduceKeysToInt(long parallelismThreshold,
            ToIntFunction<? super K> transformer,
            int basis,
            IntBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceKeysToIntTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    public void forEachValue(long parallelismThreshold,
            Consumer<? super V> action){
        if(action == null)
            throw new NullPointerException();
        new ForEachValueTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 action).invoke();
    }

    public <U> void forEachValue(long parallelismThreshold,
            Function<? super V, ? extends U> transformer,
            Consumer<? super U> action){
        if(transformer == null || action == null)
            throw new NullPointerException();
        new ForEachTransformedValueTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 transformer, action).invoke();
    }

    public <U> U searchValues(long parallelismThreshold,
            Function<? super V, ? extends U> searchFunction){
        if(searchFunction == null) throw new NullPointerException();
        return new SearchValuesTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 searchFunction, new AtomicReference<U>()).invoke();
    }

    public V reduceValues(long parallelismThreshold,
            BiFunction<? super V, ? super V, ? extends V> reducer){
        if(reducer == null) throw new NullPointerException();
        return new ReduceValuesTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, reducer).invoke();
    }

    public <U> U reduceValues(long parallelismThreshold,
            Function<? super V, ? extends U> transformer,
            BiFunction<? super U, ? super U, ? extends U> reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceValuesTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, reducer).invoke();
    }

    /**
     * Returns the result of accumulating the given transformation
     * of all values using the given reducer to combine values,
     * and the given basis as an identity value.
     *
     * @param parallelismThreshold the (estimated) number of elements
     *                             needed for this operation to be executed in parallel
     * @param transformer          a function returning the transformation
     *                             for an element
     * @param basis                the identity (initial default value) for the reduction
     * @param reducer              a commutative associative combining function
     * @return the result of accumulating the given transformation
     * of all values
     * @since 1.8
     */
    public double reduceValuesToDouble(long parallelismThreshold,
            ToDoubleFunction<? super V> transformer,
            double basis,
            DoubleBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceValuesToDoubleTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    public long reduceValuesToLong(long parallelismThreshold,
            ToLongFunction<? super V> transformer,
            long basis,
            LongBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceValuesToLongTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    public int reduceValuesToInt(long parallelismThreshold,
            ToIntFunction<? super V> transformer,
            int basis,
            IntBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceValuesToIntTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    public void forEachEntry(long parallelismThreshold,
            Consumer<? super Map.Entry<K, V>> action){
        if(action == null) throw new NullPointerException();
        new ForEachEntryTask<K, V>(null, batchFor(parallelismThreshold), 0, 0, table,
                                   action).invoke();
    }

    public <U> void forEachEntry(long parallelismThreshold,
            Function<Map.Entry<K, V>, ? extends U> transformer,
            Consumer<? super U> action){
        if(transformer == null || action == null)
            throw new NullPointerException();
        new ForEachTransformedEntryTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 transformer, action).invoke();
    }

    public <U> U searchEntries(long parallelismThreshold,
            Function<Map.Entry<K, V>, ? extends U> searchFunction){
        if(searchFunction == null) throw new NullPointerException();
        return new SearchEntriesTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 searchFunction, new AtomicReference<U>()).invoke();
    }

    public Map.Entry<K, V> reduceEntries(long parallelismThreshold,
            BiFunction<Map.Entry<K, V>, Map.Entry<K, V>, ? extends Map.Entry<K, V>> reducer){
        if(reducer == null) throw new NullPointerException();
        return new ReduceEntriesTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, reducer).invoke();
    }

    public <U> U reduceEntries(long parallelismThreshold,
            Function<Map.Entry<K, V>, ? extends U> transformer,
            BiFunction<? super U, ? super U, ? extends U> reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceEntriesTask<K, V, U>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, reducer).invoke();
    }

    public double reduceEntriesToDouble(long parallelismThreshold,
            ToDoubleFunction<Map.Entry<K, V>> transformer,
            double basis,
            DoubleBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceEntriesToDoubleTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    public long reduceEntriesToLong(long parallelismThreshold,
            ToLongFunction<Map.Entry<K, V>> transformer,
            long basis,
            LongBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceEntriesToLongTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    public int reduceEntriesToInt(long parallelismThreshold,
            ToIntFunction<Map.Entry<K, V>> transformer,
            int basis,
            IntBinaryOperator reducer){
        if(transformer == null || reducer == null)
            throw new NullPointerException();
        return new MapReduceEntriesToIntTask<K, V>
                (null, batchFor(parallelismThreshold), 0, 0, table,
                 null, transformer, basis, reducer).invoke();
    }

    // 用于视图的内部静态类
    abstract static class CollectionView<K, V, E>
            implements Collection<E>, java.io.Serializable {
        private static final long serialVersionUID = 7249069246763182397L;
        final ConcurrentHashMap<K, V> map;

        CollectionView(ConcurrentHashMap<K, V> map){ this.map = map; }

        /**
         * Returns the map backing this view.
         *
         * @return the map backing this view
         */
        public ConcurrentHashMap<K, V> getMap(){ return map; }

        /**
         * Removes all of the elements from this view, by removing all
         * the mappings from the map backing this view.
         */
        public final void clear(){ map.clear(); }

        public final int size(){ return map.size(); }

        public final boolean isEmpty(){ return map.isEmpty(); }

        // implementations below rely on concrete classes supplying these
        // abstract methods

        /**
         * Returns an iterator over the elements in this collection.
         *
         * <p>The returned iterator is
         * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
         *
         * @return an iterator over the elements in this collection
         */
        public abstract Iterator<E> iterator();

        public abstract boolean contains(Object o);

        public abstract boolean remove(Object o);

        private static final String oomeMsg = "Required array size too large";

        public final Object[] toArray(){
            long sz = map.mappingCount();
            if(sz > MAX_ARRAY_SIZE)
                throw new OutOfMemoryError(oomeMsg);
            int n = (int) sz;
            Object[] r = new Object[n];
            int i = 0;
            for(E e : this){
                if(i == n){
                    if(n >= MAX_ARRAY_SIZE)
                        throw new OutOfMemoryError(oomeMsg);
                    if(n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
                        n = MAX_ARRAY_SIZE;
                    else
                        n += (n >>> 1) + 1;
                    r = Arrays.copyOf(r, n);
                }
                r[i++] = e;
            }
            return (i == n) ? r : Arrays.copyOf(r, i);
        }

        @SuppressWarnings("unchecked")
        public final <T> T[] toArray(T[] a){
            long sz = map.mappingCount();
            if(sz > MAX_ARRAY_SIZE)
                throw new OutOfMemoryError(oomeMsg);
            int m = (int) sz;
            T[] r = (a.length >= m) ? a :
                    (T[]) java.lang.reflect.Array
                            .newInstance(a.getClass().getComponentType(), m);
            int n = r.length;
            int i = 0;
            for(E e : this){
                if(i == n){
                    if(n >= MAX_ARRAY_SIZE)
                        throw new OutOfMemoryError(oomeMsg);
                    if(n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
                        n = MAX_ARRAY_SIZE;
                    else
                        n += (n >>> 1) + 1;
                    r = Arrays.copyOf(r, n);
                }
                r[i++] = (T) e;
            }
            if(a == r && i < n){
                r[i] = null; // null-terminate
                return r;
            }
            return (i == n) ? r : Arrays.copyOf(r, i);
        }

        /**
         * Returns a string representation of this collection.
         * The string representation consists of the string representations
         * of the collection's elements in the order they are returned by
         * its iterator, enclosed in square brackets ({@code "[]"}).
         * Adjacent elements are separated by the characters {@code ", "}
         * (comma and space).  Elements are converted to strings as by
         * {@link String#valueOf(Object)}.
         *
         * @return a string representation of this collection
         */
        public final String toString(){
            StringBuilder sb = new StringBuilder();
            sb.append('[');
            Iterator<E> it = iterator();
            if(it.hasNext()){
                for(; ; ){
                    Object e = it.next();
                    sb.append(e == this ? "(this Collection)" : e);
                    if(!it.hasNext())
                        break;
                    sb.append(',').append(' ');
                }
            }
            return sb.append(']').toString();
        }

        public final boolean containsAll(Collection<?> c){
            if(c != this){
                for(Object e : c){
                    if(e == null || !contains(e))
                        return false;
                }
            }
            return true;
        }

        public final boolean removeAll(Collection<?> c){
            if(c == null) throw new NullPointerException();
            boolean modified = false;
            for(Iterator<E> it = iterator(); it.hasNext(); ){
                if(c.contains(it.next())){
                    it.remove();
                    modified = true;
                }
            }
            return modified;
        }

        public final boolean retainAll(Collection<?> c){
            if(c == null) throw new NullPointerException();
            boolean modified = false;
            for(Iterator<E> it = iterator(); it.hasNext(); ){
                if(!c.contains(it.next())){
                    it.remove();
                    modified = true;
                }
            }
            return modified;
        }

    }

    public static class KeySetView<K, V> extends CollectionView<K, V, K>
            implements Set<K>, java.io.Serializable {
        private static final long serialVersionUID = 7249069246763182397L;
        private final V value;

        KeySetView(ConcurrentHashMap<K, V> map, V value){  // non-public
            super(map);
            this.value = value;
        }

        /**
         * Returns the default mapped value for additions,
         * or {@code null} if additions are not supported.
         *
         * @return the default mapped value for additions, or {@code null}
         * if not supported
         */
        public V getMappedValue(){ return value; }

        /**
         * {@inheritDoc}
         *
         * @throws NullPointerException if the specified key is null
         */
        public boolean contains(Object o){ return map.containsKey(o); }

        /**
         * Removes the key from this map view, by removing the key (and its
         * corresponding value) from the backing map.  This method does
         * nothing if the key is not in the map.
         *
         * @param o the key to be removed from the backing map
         * @return {@code true} if the backing map contained the specified key
         * @throws NullPointerException if the specified key is null
         */
        public boolean remove(Object o){ return map.remove(o) != null; }

        /**
         * @return an iterator over the keys of the backing map
         */
        public Iterator<K> iterator(){
            Node<K, V>[] t;
            ConcurrentHashMap<K, V> m = map;
            int f = (t = m.table) == null ? 0 : t.length;
            return new KeyIterator<K, V>(t, f, 0, f, m);
        }

        /**
         * Adds the specified key to this set view by mapping the key to
         * the default mapped value in the backing map, if defined.
         *
         * @param e key to be added
         * @return {@code true} if this set changed as a result of the call
         * @throws NullPointerException          if the specified key is null
         * @throws UnsupportedOperationException if no default mapped value
         *                                       for additions was provided
         */
        public boolean add(K e){
            V v;
            if((v = value) == null)
                throw new UnsupportedOperationException();
            return map.putVal(e, v, true) == null;
        }

        /**
         * Adds all of the elements in the specified collection to this set,
         * as if by calling {@link #add} on each one.
         *
         * @param c the elements to be inserted into this set
         * @return {@code true} if this set changed as a result of the call
         * @throws NullPointerException          if the collection or any of its
         *                                       elements are {@code null}
         * @throws UnsupportedOperationException if no default mapped value
         *                                       for additions was provided
         */
        public boolean addAll(Collection<? extends K> c){
            boolean added = false;
            V v;
            if((v = value) == null)
                throw new UnsupportedOperationException();
            for(K e : c){
                if(map.putVal(e, v, true) == null)
                    added = true;
            }
            return added;
        }

        public int hashCode(){
            int h = 0;
            for(K e : this){ h += e.hashCode(); }
            return h;
        }

        public boolean equals(Object o){
            Set<?> c;
            return ((o instanceof Set) &&
                    ((c = (Set<?>) o) == this ||
                     (containsAll(c) && c.containsAll(this))));
        }

        public Spliterator<K> spliterator(){
            Node<K, V>[] t;
            ConcurrentHashMap<K, V> m = map;
            long n = m.sumCount();
            int f = (t = m.table) == null ? 0 : t.length;
            return new KeySpliterator<K, V>(t, f, 0, f, n < 0L ? 0L : n);
        }

        public void forEach(Consumer<? super K> action){
            if(action == null) throw new NullPointerException();
            Node<K, V>[] t;
            if((t = map.table) != null){
                Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
                for(Node<K, V> p; (p = it.advance()) != null; ){ action.accept(p.key); }
            }
        }
    }

    static final class ValuesView<K, V> extends CollectionView<K, V, V>
            implements Collection<V>, java.io.Serializable {
        private static final long serialVersionUID = 2249069246763182397L;

        ValuesView(ConcurrentHashMap<K, V> map){ super(map); }

        public final boolean contains(Object o){
            return map.containsValue(o);
        }

        public final boolean remove(Object o){
            if(o != null){
                for(Iterator<V> it = iterator(); it.hasNext(); ){
                    if(o.equals(it.next())){
                        it.remove();
                        return true;
                    }
                }
            }
            return false;
        }

        public final Iterator<V> iterator(){
            ConcurrentHashMap<K, V> m = map;
            Node<K, V>[] t;
            int f = (t = m.table) == null ? 0 : t.length;
            return new ValueIterator<K, V>(t, f, 0, f, m);
        }

        public final boolean add(V e){
            throw new UnsupportedOperationException();
        }

        public final boolean addAll(Collection<? extends V> c){
            throw new UnsupportedOperationException();
        }

        public Spliterator<V> spliterator(){
            Node<K, V>[] t;
            ConcurrentHashMap<K, V> m = map;
            long n = m.sumCount();
            int f = (t = m.table) == null ? 0 : t.length;
            return new ValueSpliterator<K, V>(t, f, 0, f, n < 0L ? 0L : n);
        }

        public void forEach(Consumer<? super V> action){
            if(action == null) throw new NullPointerException();
            Node<K, V>[] t;
            if((t = map.table) != null){
                Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
                for(Node<K, V> p; (p = it.advance()) != null; ){ action.accept(p.val); }
            }
        }
    }

    static final class EntrySetView<K, V> extends CollectionView<K, V, Map.Entry<K, V>>
            implements Set<Map.Entry<K, V>>, java.io.Serializable {
        private static final long serialVersionUID = 2249069246763182397L;

        EntrySetView(ConcurrentHashMap<K, V> map){ super(map); }

        public boolean contains(Object o){
            Object k, v, r;
            Map.Entry<?, ?> e;
            return ((o instanceof Map.Entry) &&
                    (k = (e = (Map.Entry<?, ?>) o).getKey()) != null &&
                    (r = map.get(k)) != null &&
                    (v = e.getValue()) != null &&
                    (v == r || v.equals(r)));
        }

        public boolean remove(Object o){
            Object k, v;
            Map.Entry<?, ?> e;
            return ((o instanceof Map.Entry) &&
                    (k = (e = (Map.Entry<?, ?>) o).getKey()) != null &&
                    (v = e.getValue()) != null &&
                    map.remove(k, v));
        }

        /**
         * @return an iterator over the entries of the backing map
         */
        public Iterator<Map.Entry<K, V>> iterator(){
            ConcurrentHashMap<K, V> m = map;
            Node<K, V>[] t;
            int f = (t = m.table) == null ? 0 : t.length;
            return new EntryIterator<K, V>(t, f, 0, f, m);
        }

        public boolean add(Entry<K, V> e){
            return map.putVal(e.getKey(), e.getValue(), false) == null;
        }

        public boolean addAll(Collection<? extends Entry<K, V>> c){
            boolean added = false;
            for(Entry<K, V> e : c){
                if(add(e))
                    added = true;
            }
            return added;
        }

        public final int hashCode(){
            int h = 0;
            Node<K, V>[] t;
            if((t = map.table) != null){
                Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
                for(Node<K, V> p; (p = it.advance()) != null; ){
                    h += p.hashCode();
                }
            }
            return h;
        }

        public final boolean equals(Object o){
            Set<?> c;
            return ((o instanceof Set) &&
                    ((c = (Set<?>) o) == this ||
                     (containsAll(c) && c.containsAll(this))));
        }

        public Spliterator<Map.Entry<K, V>> spliterator(){
            Node<K, V>[] t;
            ConcurrentHashMap<K, V> m = map;
            long n = m.sumCount();
            int f = (t = m.table) == null ? 0 : t.length;
            return new EntrySpliterator<K, V>(t, f, 0, f, n < 0L ? 0L : n, m);
        }

        public void forEach(Consumer<? super Map.Entry<K, V>> action){
            if(action == null) throw new NullPointerException();
            Node<K, V>[] t;
            if((t = map.table) != null){
                Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
                for(Node<K, V> p; (p = it.advance()) != null; ){ action.accept(new MapEntry<K, V>(p.key, p.val, map)); }
            }
        }

    }

    // -------------------------------------------------------

    @SuppressWarnings("serial")
    abstract static class BulkTask<K, V, R> extends CountedCompleter<R> {
        Node<K, V>[] tab;        // same as Traverser
        Node<K, V> next;
        TableStack<K, V> stack, spare;
        int index;
        int baseIndex;
        int baseLimit;
        final int baseSize;
        int batch;              // split control

        BulkTask(BulkTask<K, V, ?> par, int b, int i, int f, Node<K, V>[] t){
            super(par);
            this.batch = b;
            this.index = this.baseIndex = i;
            if((this.tab = t) == null)
                this.baseSize = this.baseLimit = 0;
            else if(par == null)
                this.baseSize = this.baseLimit = t.length;
            else{
                this.baseLimit = f;
                this.baseSize = par.baseSize;
            }
        }

        /**
         * Same as Traverser version
         */
        final Node<K, V> advance(){
            Node<K, V> e;
            if((e = next) != null)
                e = e.next;
            for(; ; ){
                Node<K, V>[] t;
                int i, n;
                if(e != null)
                    return next = e;
                if(baseIndex >= baseLimit || (t = tab) == null ||
                   (n = t.length) <= (i = index) || i < 0)
                    return next = null;
                if((e = tabAt(t, i)) != null && e.hash < 0){
                    if(e instanceof ForwardingNode){
                        tab = ((ForwardingNode<K, V>) e).nextTable;
                        e = null;
                        pushState(t, i, n);
                        continue;
                    }else if(e instanceof TreeBin)
                        e = ((TreeBin<K, V>) e).first;
                    else
                        e = null;
                }
                if(stack != null)
                    recoverState(n);
                else if((index = i + baseSize) >= n)
                    index = ++baseIndex;
            }
        }

        private void pushState(Node<K, V>[] t, int i, int n){
            TableStack<K, V> s = spare;
            if(s != null)
                spare = s.next;
            else
                s = new TableStack<K, V>();
            s.tab = t;
            s.length = n;
            s.index = i;
            s.next = stack;
            stack = s;
        }

        private void recoverState(int n){
            TableStack<K, V> s;
            int len;
            while ((s = stack) != null && (index += (len = s.length)) >= n) {
                n = len;
                index = s.index;
                tab = s.tab;
                s.tab = null;
                TableStack<K, V> next = s.next;
                s.next = spare; // save for reuse
                stack = next;
                spare = s;
            }
            if(s == null && (index += baseSize) >= n)
                index = ++baseIndex;
        }
    }

    //Task,这里删除许多同含义方法
    @SuppressWarnings("serial")
    static final class ForEachKeyTask<K, V>
            extends BulkTask<K, V, Void> {
        final Consumer<? super K> action;

        ForEachKeyTask
                (BulkTask<K, V, ?> p, int b, int i, int f, Node<K, V>[] t,
                        Consumer<? super K> action){
            super(p, b, i, f, t);
            this.action = action;
        }

        public final void compute(){
            final Consumer<? super K> action;
            if((action = this.action) != null){
                for(int i = baseIndex, f, h; batch > 0 &&
                                             (h = ((f = baseLimit) + i) >>> 1) > i; ){
                    addToPendingCount(1);
                    new ForEachKeyTask<K, V>
                            (this, batch >>>= 1, baseLimit = h, f, tab,
                             action).fork();
                }
                for(Node<K, V> p; (p = advance()) != null; ){ action.accept(p.key); }
                propagateCompletion();
            }
        }
    }


    // Unsafe mechanics
    private static final sun.misc.Unsafe U;
    private static final long SIZECTL;
    private static final long TRANSFERINDEX;
    private static final long BASECOUNT;
    private static final long CELLSBUSY;
    private static final long CELLVALUE;
    private static final long ABASE;
    private static final int ASHIFT;

    static{
        try {
            U = sun.misc.Unsafe.getUnsafe();
            Class<?> k = ConcurrentHashMap.class;
            SIZECTL = U.objectFieldOffset
                    (k.getDeclaredField("sizeCtl"));
            TRANSFERINDEX = U.objectFieldOffset
                    (k.getDeclaredField("transferIndex"));
            BASECOUNT = U.objectFieldOffset
                    (k.getDeclaredField("baseCount"));
            CELLSBUSY = U.objectFieldOffset
                    (k.getDeclaredField("cellsBusy"));
            Class<?> ck = CounterCell.class;
            CELLVALUE = U.objectFieldOffset
                    (ck.getDeclaredField("value"));
            Class<?> ak = Node[].class;
            ABASE = U.arrayBaseOffset(ak);
            int scale = U.arrayIndexScale(ak);
            if((scale & (scale - 1)) != 0)
                throw new Error("data type scale not a power of two");
            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
        } catch (Exception e) {
            throw new Error(e);
        }
    }
}