众所周知 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数据结构很简单,从上可知,就是一个链表,可是只容许对数据进行查找,不容许进行修改