衆所周知 HashMap 的查找效率爲O(1)。可是HashMap非線程安全,在併發狀況下,擴容時可能破壞鏈表的指針,造成環狀鏈。數組
Hashtable 是線程安全的。看一下 Hashtable 的源碼安全
get操做數據結構
put 操做併發
get 和 put 操做 都是經過加 synchronized 來實現線程安全的。至關於給整個hash 表加了一把鎖。就算線程都是讀操做,也是互斥的。性能比較差。高併發
在JDK 1.6 的版本中採用鎖分段的機制,實現高併發。底層採用 數組+鏈表+紅黑樹的數據結構。性能
Segment 經過繼承ReentrantLock 來實現加鎖優化
JDK 1.8 中拋棄了上面的數據結構,採用CAS+Synchronized來保證併發更新的安全,底層仍然採用this
數組+鏈表+紅黑樹的數據結構。整個看起來像是優化的Hashtable。spa
/** * Key-value entry. This class is never exported out as a * user-mutable Map.Entry (i.e., one supporting setValue; see * MapEntry below), but can be used for read-only traversals used * in bulk tasks. Subclasses of Node with a negative hash field * are special, and contain null keys and values (but are never * exported). Otherwise, keys and vals are never null. */ 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; } // 不容許進行set 操做 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))); } /** * Virtualized support for map.get(); overridden in subclasses. */ 至關於map 的 get() 方法 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; } }
能夠看到 volatile V val; volatile Node<K,V> next; 線程
val 和 next 在擴容時會發生變化,加上volatile 來保證內存的可見性和禁止指令的重排序
Node數據結構很簡單,從上可知,就是一個鏈表,可是隻容許對數據進行查找,不容許進行修改