1、个人总结及想法:
(1)1.8相比较于1.7的变化?
HashMap的底层数据结构大家应该都比较清楚了,就是数组+链表,链表主要用来解决hash冲突,使用了链地址法的方式来解决,1.8的改动主要就是hash冲突时候,一是在进行链表插入时由1.7的头插法变成了尾插法,第二个原来链表是一个单链表,但是现在超过红黑树的阀值过后就会自动升级为红黑树,阀值是链表节点超过8个节点(建立在数组已经扩容到64,否则优先选择扩容来解决冲突)。当链表节点少于6个时红黑树会退化成普通链表。
(2)1.8会出现1.7之前并发扩容节点转移时出现死循环的过程吗?
不会,因为1.8在扩容时不再是像原来一样转移,而是分成了两个链表,然后移动到新数组的原位置和原位置+length处,这样最多可能出现重复扫描,但不会出现死循环的情况。但是依然是线程不安全的。
2、源码分析:
(1)、重要属性:
1 private static final long serialVersionUID = 362498820763181265L; 2 //默认值 3 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 4 5 //最大值 6 static final int MAXIMUM_CAPACITY = 1 << 30; 7 8 //负载因子 9 static final float DEFAULT_LOAD_FACTOR = 0.75f; 10 11 //转化为红黑树的阀值 12 static final int TREEIFY_THRESHOLD = 8; 13 14 //红黑树退化成链表阀值 15 static final int UNTREEIFY_THRESHOLD = 6; 16 17 //转化为红黑树时最小的数组大小 18 static final int MIN_TREEIFY_CAPACITY = 64; 19 20 //节点数据结构 21 static class Node<K,V> implements Map.Entry<K,V> { 22 final int hash; 23 final K key; 24 V value; 25 Node<K,V> next; 26 27 Node(int hash, K key, V value, Node<K,V> next) { 28 this.hash = hash; 29 this.key = key; 30 this.value = value; 31 this.next = next; 32 } 33 34 public final K getKey() { return key; } 35 public final V getValue() { return value; } 36 public final String toString() { return key + "=" + value; } 37 38 public final int hashCode() { 39 return Objects.hashCode(key) ^ Objects.hashCode(value); 40 } 41 42 public final V setValue(V newValue) { 43 V oldValue = value; 44 value = newValue; 45 return oldValue; 46 } 47 48 //重写了equals方法 49 public final boolean equals(Object o) { 50 if (o == this) 51 return true; 52 if (o instanceof Map.Entry) { 53 Map.Entry<?,?> e = (Map.Entry<?,?>)o; 54 if (Objects.equals(key, e.getKey()) && 55 Objects.equals(value, e.getValue())) 56 return true; 57 } 58 return false; 59 } 60