Skip to content

Latest commit

 

History

History
1071 lines (905 loc) · 37.2 KB

File metadata and controls

1071 lines (905 loc) · 37.2 KB

Java JDK源码解析

声明:

本文档系作者自己的理解,如有纰漏欢迎指出,请联系jerehao@126.com

本文档中若有引用,出处作者已尽可能标明,如有漏标、误标或侵权,请联系作者更改。

转载请注明作者 jerehao 谢谢。

1. 集合类型--Map

img

1.1 AbstractMap (JDK 1.8)

Map类的 entrySet, values 和 keySet 都不是采用同步(插入删除同步)的方法实现的,而是根据迭代器生成集合的方法实现的。

entrySet

entrySet 是根据抽象方法获得,需要子类实现。

public abstract Set<Entry<K,V>> entrySet();

values

values 由 AbstractCollection 和 entrySet().iterator() 生成。

public Collection<V> values() {
    Collection<V> vals = values;
    if (vals == null) {
        vals = new AbstractCollection<V>() { //抽象集合
            public Iterator<V> iterator() {
                return new Iterator<V>() {
                    private Iterator<Entry<K,V>> i = entrySet().iterator();

                    public boolean hasNext() {
                        return i.hasNext();
                    }

                    public V next() {
                        return i.next().getValue();
                    }

                    public void remove() {
                        i.remove();
                    }
                };
            }

            public int size() {
                return AbstractMap.this.size();
            }

            public boolean isEmpty() {
                return AbstractMap.this.isEmpty();
            }

            public void clear() {
                AbstractMap.this.clear();
            }

            public boolean contains(Object v) {
                return AbstractMap.this.containsValue(v);
            }
        };
        values = vals;
    }
    return vals;
}

keySet

values 由 AbstractSet和 entrySet().iterator() 生成。

public Set<K> keySet() {
    Set<K> ks = keySet;
    if (ks == null) {
        ks = new AbstractSet<K>() {	// 抽象Set
            public Iterator<K> iterator() {
                return new Iterator<K>() {
                    private Iterator<Entry<K,V>> i = entrySet().iterator();

                    public boolean hasNext() {
                        return i.hasNext();
                    }

                    public K next() {
                        return i.next().getKey();
                    }

                    public void remove() {
                        i.remove();
                    }
                };
            }

            public int size() {
                return AbstractMap.this.size();
            }

            public boolean isEmpty() {
                return AbstractMap.this.isEmpty();
            }

            public void clear() {
                AbstractMap.this.clear();
            }

            public boolean contains(Object k) {
                return AbstractMap.this.containsKey(k);
            }
        };
        keySet = ks;
    }
    return ks;
}

1.1 HashMap(JDK 1.8)

存储结构

HashMap使用数组+链表+红黑树的方式存储,链表和红黑树是用来处理哈希冲突的数据结构。

数组的每个元素称之为桶(bucket)或箱(bin),以下统一称之为箱,每个箱通过链表或红黑树的结构可以容纳若干个结点值。使用Node<K,V>[] table表示箱数组,存储链表的第一个结点或红黑树的根结点,当没有结点是存储null,具体结构和结构实现:

transient Node<K,V>[] table;	//箱数组

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;		//链表的next指针

    //方法省略......
}

箱数组有默认的初始化大小static final int DEFAULT_INITIAL_CAPACITY = 1 << 4,也可以通过构造函数设置初始化大小,若这个值不为2的次幂,则会通过一系列位移操作,使之转化为比这个值大且最接近这个值的2次幂值,具体实现看下面的源码:

static final int tableSizeFor(int cap) {
    int n = cap - 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;
}

上面的源码的一系列位移操作实质就是将cap - 1二进制表示最高位的1之后全部用1填满,最后再加1就得到了大于等于cap且最近进cap的2次幂数。第8行源码也可以看出箱数组长度最小为1,最大为static final int MAXIMUM_CAPACITY = 1 << 30;

理想情况下,箱数组中每个箱最多装有一个结点,查找复杂度为 O(1) 。但哈希冲突目前是不可避免的,一旦冲突每个箱就要存多个结点,当结点个数越多,平均查找长度就越大。当结点较少时,HashMap使用链表处理冲突,当结点数超过一定的个数时,HashMap就会执行树形化或扩容的操作(请查看树形化扩容),树形化后的树结点结构要比链表结点复杂,树结点继承了链表结点,具体源码:

static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
    TreeNode<K,V> parent;  	// 父结点
    TreeNode<K,V> left;		// 左子结点
    TreeNode<K,V> right;	// 右子结点
    TreeNode<K,V> prev;    	// 前一个结点,与next相对
    boolean red; 			// 颜色
    
    //方法省略......
}

//LinkedHashMap.Entry<K,V> 实现
static class Entry<K,V> extends HashMap.Node<K,V> {
    Entry<K,V> before, after;	//记录插入顺序
    
    //方法省略......
}

构造函数

HashMap有4个构造函数,其中前三个功能相同,只是默认参数的重载,第四个是根据一个已有Map初始化HashMap。

	public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)	//初始化容量不合法,这里容量即箱数组长度
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)	//初始化容量超过最大值
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))	//装填因子不合法
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }

    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
    }

    public HashMap(Map<? extends K, ? extends V> m) {	//根据已有Map初始化
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }

    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // 初始化参数
                float ft = ((float)s / loadFactor) + 1.0F; //求初始化箱数组长度
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t > threshold)	//重置门限值,即初始化箱数组长度
                    threshold = tableSizeFor(t);
            }
            else if (s > threshold) //扩容
                resize();
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);
            }
        }
    }

可以看到HashMap的构造函数只是设置了初始化参数,实际申请箱数组空间是在第一次 put/merge/compute/computeIfAbsent 值之后。

put 操作

这里直接看源码,注意哈希值的计算方法。

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

//重新计算哈希值
static final int hash(Object key) {
    int h;
    //使用高16位异或低16位,确保在箱数组大小小于2的16次方前让高位也参与到哈希中来
    //好处是当低位相同时,高位可以避免过早的冲突发生
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)	//箱数组长度为0时初始化
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null)	// (n - 1) & hash 相当于 hash % n
        tab[i] = newNode(hash, key, value, null);	// 此箱还没有结点
    else {
        Node<K,V> e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k)))) //存在完全相同的key
            e = p;
        else if (p instanceof TreeNode)	//树型箱
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {	//链型箱
            for (int binCount = 0; ; ++binCount) { //遍历链表找链表最后一个元素插入
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // 插入后,此箱达到树形化阈值
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { //存在完全相同的key,更新value值
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)	//仅空缺时更改位false 或 value为null
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold) //总结点数达到门限值
        resize();
    afterNodeInsertion(evict);
    return null;
}

以上可以知道,保证箱数组长度(源码中使用 n 表示)为2的次幂大小的优点之一就是,可以使用位操作(n - 1) & hash代替求余操作hash % n。另一个比较重要的优点就是优化了扩容时重新分配结点位置的操作。

// 下面的hash值都是经过高16位异或低16位后的值
hash1 = 00000000 00000000 00000000 10100101
hash2 = 00000000 00000000 00000000 10110101
// n = 16 时,hash1和hash2的箱数组下标分别为
hash1 & 16 - 1 = hash1 & 1111 = 0101
hash2 & 16 - 1 = hash2 & 1111 = 0101
//此时它们在一个箱中,当发生扩容时,n = 32,hash1和hash2的箱数组下标又分别为
hash1 & 32 - 1 = hash1 & 11111 = 00101
hash2 & 32 - 1 = hash2 & 11111 = 10101
//也就是hash1仍在原来的箱中,而hash2位于原来的箱数组下标+16位置的箱中
//每次扩容时,每个结点只有两种可能,要么在原来的箱中,要么在原来的位置+原箱数组大小的位置的箱中,
//取决于而这求余最高为位0还是为1,这个判断只需要用 hash & n 即可,
//对于上例,也就是hash & 16,得到0则扩容32后仍在原箱,否则在原位+16后的高位箱

删除操作

public V remove(Object key) {
    Node<K,V> e;
    return (e = removeNode(hash(key), key, null, false, true)) == null ?
        null : e.value;
}

final Node<K,V> removeNode(int hash, Object key, Object value,
                           boolean matchValue, boolean movable) {
    Node<K,V>[] tab; Node<K,V> p; int n, index;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (p = tab[index = (n - 1) & hash]) != null) { //可能含有要删除的Key
        Node<K,V> node = null, e; K k; V v;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))	//找到完全相同的Key
            node = p;
        else if ((e = p.next) != null) {	//遍历查找
            if (p instanceof TreeNode)
                node = ((TreeNode<K,V>)p).getTreeNode(hash, key);	//树型查找
            else {
                do {	//链型查找
                    if (e.hash == hash &&
                        ((k = e.key) == key ||
                         (key != null && key.equals(k)))) {
                        node = e;
                        break;
                    }
                    p = e;
                } while ((e = e.next) != null);
            }
        }
        if (node != null && (!matchValue || (v = node.value) == value ||
                             (value != null && value.equals(v)))) {	//符合结点删除条件
            if (node instanceof TreeNode)
                ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);	//树型删除,
            												//可能会有逆树型化操作
            else if (node == p)	//是头结点
                tab[index] = node.next;
            else
                p.next = node.next;
            ++modCount;
            --size;
            afterNodeRemoval(node);
            return node;
        }
    }
    return null;
}

//删除所有元素
public void clear() {
    Node<K,V>[] tab;
    modCount++;
    if ((tab = table) != null && size > 0) {
        size = 0;
        for (int i = 0; i < tab.length; ++i)	//直接遍历清空置null
            tab[i] = null;
    }
}

清空所有元素时,直接遍历数组设 null 值即可。

查找操作

public V get(Object key) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}

final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        if (first.hash == hash && // 总是检查第一个结点是否是目标结点
            ((k = first.key) == key || (key != null && key.equals(k))))
            return first;
        if ((e = first.next) != null) {
            if (first instanceof TreeNode)
                return ((TreeNode<K,V>)first).getTreeNode(hash, key);	//树型查找
            do { //链型查找
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
}

static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
    
    final TreeNode<K,V> getTreeNode(int h, Object k) {
        return ((parent != null) ? root() : this).find(h, k, null);
    }
    
    final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
        TreeNode<K,V> p = this;
        do {
            int ph, dir; K pk;
            TreeNode<K,V> pl = p.left, pr = p.right, q;
            if ((ph = p.hash) > h) // h 小
                p = pl;
            else if (ph < h) //h 大
                p = pr;
            else if ((pk = p.key) == k || (k != null && k.equals(pk))) // h 相同,且值相同
                return p;
            else if (pl == null) //h 相同,值不同
                p = pr;
            else if (pr == null) //h 相同,值不同
                p = pl;
            else if ((kc != null ||
                      (kc = comparableClassFor(k)) != null) &&	 //h 相同,左右子都不为 null
                     (dir = compareComparables(kc, k, pk)) != 0) //根据Comparable接口比大小
                p = (dir < 0) ? pl : pr;
            else if ((q = pr.find(h, k, kc)) != null) 	//h 相同,也没实现Comparable接口,
                return q;                				//右子树遍历查找
            else //h 相同,也没实现Comparable接口,左子树遍历查找
                p = pl;
        } while (p != null);
        return null;
    }
}

树形化

树形化有两个关键的参数,一个是树形化限值static final int TREEIFY_THRESHOLD = 8,一个是最小树形化容量static final int MIN_TREEIFY_CAPACITY = 64。当冲突的结点数达到 TREEIFY_THRESHOLD 时,并不一定会树形化,若箱数组长度小于 MIN_TREEIFY_CAPACITY 则会执行扩容操作(扩容后若冲突结点数量未发生变化即仍达到 TREEIFY_THRESHOLD ,则会等到下一次插入到此冲突箱时执行树形化,所以树形化时冲突结点数目可能为 8,9,10或11,当然 9,10,11 的情况发生概率很小)。

所以树形化条件是:某次 put/merge/compute/computeIfAbsent 后,某个箱的链表长度大于等于 TREEIFY_THRESHOLD 且 箱数组长度大于等于 MIN_TREEIFY_CAPACITY。

树形化源码:

final void treeifyBin(Node<K,V>[] tab, int hash) {
    int n, index; Node<K,V> e;
    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) 
        resize();								//小于MIN_TREEIFY_CAPACITY执行扩容
    else if ((e = tab[index = (n - 1) & hash]) != null) {
        TreeNode<K,V> hd = null, tl = null;
        //do while 循环主要将链表转化为双链表
        do {
            TreeNode<K,V> p = replacementTreeNode(e, null);	//转化链表结点为树结点
            if (tl == null)
                hd = p;		//头结点
            else {
                p.prev = tl;
                tl.next = p;
            }
            tl = p;		//记录当前结点,供下一个结点设置 prev 域
        } while ((e = e.next) != null);
        if ((tab[index] = hd) != null)
            hd.treeify(tab);	//双链表转红黑树,同时会将红黑树的根结点放在箱数组上
    }
}

// For treeifyBin
TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
    return new TreeNode<>(p.hash, p.key, p.value, next);
}

由源码总结树形化具体操作为:

  1. 将链表转为双链表(同时链表结点转为树结点)
  2. 双链表转红黑树
  3. 将红黑树根结点放到箱数组上

逆树形化(链表化)

当删除一个树结点或扩容时,箱的树结点数目可能会减小,当数目小于等于static final int UNTREEIFY_THRESHOLD = 6时会发生逆树形化,即将红黑树转为链表,UNTREEIFY_THRESHOLD 为 6 不为 8 是防止频繁的发生树形化和逆树形化。

可知逆树形化条件是:删除一个树结点或扩容时,箱的树结点数目小于等于 UNTREEIFY_THRESHOLD 。

逆树形化源码:

final Node<K,V> untreeify(HashMap<K,V> map) {
    Node<K,V> hd = null, tl = null;
    for (Node<K,V> q = this; q != null; q = q.next) {
        Node<K,V> p = map.replacementNode(q, null);
        if (tl == null)
            hd = p;
        else
            tl.next = p;
        tl = p;
    }
    return hd;
}

可以看到红黑树转为链表非常容易,遍历 next 指针即可。

为什么不直接使用红黑树,而要使用链表和红黑树的组合呢?而且链表转红黑树的阈值为什么是8?

不直接使用红黑树因为在结点数目较少时,链表和红黑树的查找相差很小,而红黑树的插入和删除要比链表复杂,相比较对性能就会大点,且一般认为需要使用红黑树的几率很小,使用红黑树JDK是希望当最坏情况下也有较好的查询性能。

那为什么是8呢?个人认为是经验数值还有程序员对2的次幂数的偏爱。///TODO

扩容

上面的树形化已经说明了一种发生扩容的时机是,某次 put/merge/compute/computeIfAbsent 时某个箱冲突结点达到 TREEIFY_THRESHOLD,但箱箱数组长度小于 MIN_TREEIFY_CAPACITY。另一个发生扩容的时机是,当某次 put/merge/compute/computeIfAbsent 后,HashMap的总结点数量大于 门限值 threshold 时,会发生扩容。这个门限值初始就为 DEFAULT_INITIAL_CAPACITY 或自定义大小,当第一次 put/merge/compute/computeIfAbsent时(第一 put/merge/compute/computeIfAbsent 之前箱数组不会被设置,一直为空),会执行下面这个 resize 方法,执行后生成的新箱箱数组长度就为这个旧门限值,新门限值为新箱箱数组长度乘以装填因子(可以再构造函数自定义,默认为static final float DEFAULT_LOAD_FACTOR = 0.75f),此后每次扩容都将箱箱数组长度扩大一倍,门下值扩大一倍,即可以使用左移代替乘以2。

扩容源码:

final Node<K,V>[] resize() {
    Node<K,V>[] oldTab = table;
    int oldCap = (oldTab == null) ? 0 : oldTab.length;	// 旧箱箱数组长度
    int oldThr = threshold;		// 旧门限值
    int newCap, newThr = 0;
    if (oldCap > 0) {	// 若旧箱数组不为空
        if (oldCap >= MAXIMUM_CAPACITY) {	// 若旧箱箱数组长度达到MAXIMUM_CAPACITY,无法扩容
            threshold = Integer.MAX_VALUE;	// 将门限值设为最大int
            return oldTab;
        }
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && 	//新箱箱数组长度增加一倍
                 oldCap >= DEFAULT_INITIAL_CAPACITY)	//若新箱箱数组长度未到最大,
            											//且旧箱箱数组长度大于等于8	
            newThr = oldThr << 1; 						//设新门限值为旧门限值的2倍
        												//否则门限值将在第23行根据装填因子设置
    }
    else if (oldThr > 0)	//若旧箱数组为空,但旧门限值不为0
        newCap = oldThr;	//设新箱箱数组长度为旧门限值
    else {	//若旧箱数组为空,且旧门限值也为0,那么使用默认参数初始化新箱箱数组长度和新门限值
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    if (newThr == 0) {
        float ft = (float)newCap * loadFactor;
        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);	//门限值不能超过最大int值
    }
    threshold = newThr;
    @SuppressWarnings({"rawtypes","unchecked"})
    Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];	//新箱数组
    table = newTab;
    if (oldTab != null) {	// 对旧箱的所有结点重新计算位置,
        					// 只有两种情况,保留原位,或者原位置向后移 oldCap
        for (int j = 0; j < oldCap; ++j) {
            Node<K,V> e;
            if ((e = oldTab[j]) != null) {// 获取每个箱的第一个元素,为 null 则跳过
                oldTab[j] = null;
                if (e.next == null)	// 箱子只有一个元素
                    newTab[e.hash & (newCap - 1)] = e;
                else if (e instanceof TreeNode)	// 树型箱
                    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);	//可能会逆树形化
                else { // 链型箱
                    Node<K,V> loHead = null, loTail = null;
                    Node<K,V> hiHead = null, hiTail = null;
                    Node<K,V> next;
                    do { //遍历链表,根据哈希取余的最高为,划分为两个链表
                        next = e.next;
                        if ((e.hash & oldCap) == 0) {	// 保留原位的
                            if (loTail == null)
                                loHead = e;
                            else
                                loTail.next = e;
                            loTail = e;
                        }
                        else {	//向高位移动 oldCap 的
                            if (hiTail == null)
                                hiHead = e;
                            else
                                hiTail.next = e;
                            hiTail = e;
                        }
                    } while ((e = next) != null);
                    if (loTail != null) {
                        loTail.next = null;
                        newTab[j] = loHead;
                    }
                    if (hiTail != null) {
                        hiTail.next = null;
                        newTab[j + oldCap] = hiHead;
                    }
                }
            }
        }
    }
    return newTab;
}

从上面源码总结扩容时有四种情况:

  1. 旧箱箱数组长度达到 MAXIMUM_CAPACITY 时,设门限值为最大int
  2. 旧箱箱数组长度小于 MAXIMUM_CAPACITY 且大于 0 时,箱数组和门限值同时扩大2倍
  3. 旧箱箱数组长度为0,但门限值不为 0 时,新箱数组长度为旧门限值,新门限值为新箱数组长度乘以装填因子
  4. 旧箱箱数组长度为0,且门限值为 0 时,新箱数组长度为默认大小,新门限值为新箱数组长度乘以默认装填因子

entrySet

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

final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    public final int size()                 { return size; }
    public final void clear()               { HashMap.this.clear(); }
    public final Iterator<Map.Entry<K,V>> iterator() {
        return new EntryIterator();
    }
    public final boolean contains(Object o) {
        if (!(o instanceof Map.Entry))
            return false;
        Map.Entry<?,?> e = (Map.Entry<?,?>) o;
        Object key = e.getKey();
        Node<K,V> candidate = getNode(hash(key), key);
        return candidate != null && candidate.equals(e);
    }
    public final boolean remove(Object o) {
        if (o instanceof Map.Entry) {
            Map.Entry<?,?> e = (Map.Entry<?,?>) o;
            Object key = e.getKey();
            Object value = e.getValue();
            return removeNode(hash(key), key, value, true, true) != null;
        }
        return false;
    }
    public final Spliterator<Map.Entry<K,V>> spliterator() {
        return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
    }
    public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
        Node<K,V>[] tab;
        if (action == null)
            throw new NullPointerException();
        if (size > 0 && (tab = table) != null) {
            int mc = modCount;
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next)
                    action.accept(e);
            }
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
}

final class EntryIterator extends HashIterator
            implements Iterator<Map.Entry<K,V>> {
        public final Map.Entry<K,V> next() { return nextNode(); }
    }

abstract class HashIterator {
	Node<K,V> next;        // next entry to return
	Node<K,V> current;     // current entry
 	int expectedModCount;  // for fast-fail
	int index;             // current slot

	HashIterator() {
        expectedModCount = modCount;
        Node<K,V>[] t = table; 	// 直接获取原table生成iterator
        current = next = null;
        index = 0;
        if (t != null && size > 0) { // advance to first entry
        	do {} while (index < t.length && (next = t[index++]) == null);
        }
	}

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

    final Node<K,V> nextNode() { 	// 调用next指针生成next
		Node<K,V>[] t;
		Node<K,V> e = next;
		if (modCount != expectedModCount)
      		throw new ConcurrentModificationException();
    	if (e == null)
    		throw new NoSuchElementException();
    	if ((next = (current = e).next) == null && (t = table) != null) {
    		do {} while (index < t.length && (next = t[index++]) == null);
    	}
    	return e;
    }

	public final void remove() {
		Node<K,V> p = current;
		if (p == null)
			throw new IllegalStateException();
		if (modCount != expectedModCount)
			throw new ConcurrentModificationException();
		current = null;
		K key = p.key;
		removeNode(hash(key), key, null, false, false);
		expectedModCount = modCount;
	}
}

2.锁

2.1 Lock

// 阻塞获取锁
void lock();

// 非阻塞获取锁,成功返回 true,失败返回 false
boolean tryLock();
// 阻塞时间内获取锁,返回 true,否则返回 false
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

// 阻塞获取锁,但是阻塞过程中接收中断信号
void lockInterruptibly() throws InterruptedException;

// 释放锁
void unlock();

// 用于同步的条件实例
Condition newCondition();

2.2 ReentrantLock

排它同步器

首先使用 AQS 实现了排它同步器,包括公平和不公平两种。

// 同步器
private final Sync sync;

// 这是一个排它的同步器,只能拥有线程才能操作 state
abstract static class Sync extends AbstractQueuedSynchronizer {

    // 子类实现
    abstract void lock();

    // 非公平的对 state 加 acquires
    // 成功返回true,失败返回 false
    final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) { // state 为 0 ,可以获取锁
            if (compareAndSetState(0, acquires)) { // CAS 成功则获取锁
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) { // state 不为 0,
            int nextc = c + acquires;					 // 则必须是当前线程才能操作
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }

    // 对 state 减 releases 
    protected final boolean tryRelease(int releases) {
        int c = getState() - releases;
        if (Thread.currentThread() != getExclusiveOwnerThread()) // 其他线程尝试操作,异常
            throw new IllegalMonitorStateException();
        boolean free = false;
        if (c == 0) { // 释放锁
            free = true;
            setExclusiveOwnerThread(null);
        }
        setState(c);
        return free;
    }
}

// 非公平同步器
static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;

    final void lock() {
        if (compareAndSetState(0, 1)) // 先尝试直接锁
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1); // 队列阻塞获取
    }

    // tryAcquire 方法会在 lock 时循环调用
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

// 公平同步器
static final class FairSync extends Sync {

    final void lock() {
        acquire(1);// 队列阻塞锁定
    }


    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) { // 前面没有等待,且 CAS 成功,获取锁
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) { // 拥有锁线程
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
}

上面可以看出,公平锁在获取时会判断前面是否有等待,保证的 FIFO 即公平。而非公平则不判断前面是否有等待,而是直接获取,那么锁被获取到的顺序就是随机的,即不公平。

构造函数

// 默认非公平
public ReentrantLock() {
    sync = new NonfairSync();
}

// 传参是否公平
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

加锁解锁

public void lock() {
    sync.lock();
}

public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}

public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}

public boolean tryLock(long timeout, TimeUnit unit)
    throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

public void unlock() {
    sync.release(1);
}

2.3 CountDownLatch

共享同步器

private static final class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 4982264981922014374L;

    // await 使用
    // 返回共享同步器的锁是否被完全释放了
    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }

    protected boolean tryReleaseShared(int releases) {
        // Decrement count; signal when transition to zero
        for (;;) {
            int c = getState();
            if (c == 0)
                return false;
            int nextc = c-1;
            if (compareAndSetState(c, nextc)) // CAS 释放
                return nextc == 0; // 返回释放后是否 stat 为 0
        }
    }
}

private final Sync sync;

构造方法

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

等待与自减

public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1); // 循环调用 tryAcquireShared
}

// 限制阻塞时间
public boolean await(long timeout, TimeUnit unit)
    throws InterruptedException {
    return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}

// 一个线程执行完(满足一个条件),自减
public void countDown() {
    sync.releaseShared(1);
}

2.4 CyclicBarrier

成员变量

// 循环代
private static class Generation {
        boolean broken = false; // 当前循环是否已损坏
}

// 保护栅栏入口的可重入锁
private final ReentrantLock lock = new ReentrantLock();
// 等待条件,即绊脚石
private final Condition trip = lock.newCondition();
// 参与者个数
private final int parties;
// 每次栅栏被破坏时执行的接口
private final Runnable barrierCommand;
// 当前代
private Generation generation = new Generation();
//需要等待的参与者
private int count;

构造方法

public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}

public CyclicBarrier(int parties) {
    this(parties, null);
}

**await 方法——阻塞等待下一轮循环 **

public int await() throws InterruptedException, BrokenBarrierException {
    try {
        return dowait(false, 0L);
    } catch (TimeoutException toe) {
        throw new Error(toe); // cannot happen;
    }
}

//在timeout指定的超时时间内,等待其他参与线程到达屏障点
//如果超出指定的等待时间,则抛出TimeoutException异常,如果该时间小于等于零,则此方法根本不会等待
public int await(long timeout, TimeUnit unit)
    	throws InterruptedException,BrokenBarrierException,TimeoutException {
    return dowait(true, unit.toNanos(timeout));
}

// 阻塞等待的核心方法
private int dowait(boolean timed, long nanos) 
    	throws InterruptedException, BrokenBarrierException,TimeoutException {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        final Generation g = generation;

        if (g.broken) //栅栏已损坏
            throw new BrokenBarrierException();

        if (Thread.interrupted()) { //线程被中断,破坏栅栏,并抛出中断异常
            breakBarrier();
            throw new InterruptedException();
        }

        int index = --count; // 每有一个 await() 说明有一个参与者到了
        if (index == 0) {  // 全到
            boolean ranAction = false;
            try {
                final Runnable command = barrierCommand;
                if (command != null)
                    command.run();
                ranAction = true;
                nextGeneration(); //新一代,新一轮循环
                return 0;
            } finally {
                if (!ranAction)
                    breakBarrier();
            }
        }

        // loop until tripped, broken, interrupted, or timed out
        for (;;) {
            try {
                if (!timed)
                    trip.await(); // 等待唤醒
                else if (nanos > 0L)
                    nanos = trip.awaitNanos(nanos);// 等待唤醒
            } catch (InterruptedException ie) {
                if (g == generation && ! g.broken) {
                    breakBarrier();
                    throw ie;
                } else {
                    // We're about to finish waiting even if we had not
                    // been interrupted, so this interrupt is deemed to
                    // "belong" to subsequent execution.
                    Thread.currentThread().interrupt();
                }
            }

            if (g.broken)
                throw new BrokenBarrierException();

            if (g != generation) // 唤醒后发现新一代,返回准备下轮循环
                return index;

            if (timed && nanos <= 0L) {
                breakBarrier();
                throw new TimeoutException();
            }
        }
    } finally {
        lock.unlock();
    }
}

private void nextGeneration() {
    // 唤醒被绊倒的线程
    trip.signalAll();
    // 重置为新一轮循环
    count = parties;
    generation = new Generation();
}

// 使栅栏损坏
private void breakBarrier() {
    generation.broken = true;
    count = parties;
    trip.signalAll();
}