Hashtable

PS:Hashtable。「table」 是小写开头啊!!源码白看了…

Hashtable 和 HashMap 原理是一致的。HashMap看 HashMap 源码分析

两者直观的不同之处如下。

Hashtable 线程安全,键值不能为 null。HashMap 反之…

HashMap 也可以通过下面的语句进行同步:

1
Map m = Collections.synchronizeMap(hashMap);

Hashtable 在单线程环境下比 HashMap 要慢。

如果不需要同步(只需要单一线程),HashMap 性能优于 Hashtable。

为什么呢…

追溯到线程同步…

线程同步

线程同步使用的是 synchronized 关键字。

例如:

1
2
3
4
5
6
public synchronized V put(K key, V value) {
...
}
public synchronized V remove(Object key) {
...
}

具体看多线程相关…

直觉思考,保证线程同步,一定会需要一些开销…

在无需同步的情况下,Hashtable 仍会执行某些判断(比如执行一个操作来判断某个变量是否正被别人使用…),虽然只有真正需要同步时才会执行判断后的同步逻辑。

所以若无需同步,HashMap 性能优于 Hashtable。(因为它不必执行那些判断…)

put

查看源码,发现 Hashtable 没有 HashMap 中类似

1
2
3
4
5
6
7
8
/**
* JDK1.8 新加,Entry链表最大长度,当桶中节点数目大于该长度时,将链表转成红黑树存储;
*/
static final int TREEIFY_THRESHOLD = 8;
/**
* JDK1.8 新加,当桶中节点数小于该长度,将红黑树转为链表存储;
*/
static final int UNTREEIFY_THRESHOLD = 6;

的属性。查看 put 方法,发现也没有使用到红黑树结构。

Hashtable 比之 HashMap,没有使用红黑树。

Hashtable 把新插入的元素放入 Entry 这个链表最前边。

fail-fast 迭代器

1
2
3
4
5
6
7
8
 /**
* The number of times this Hashtable has been structurally modified
* Structural modifications are those that change the number of entries in
* the Hashtable or otherwise modify its internal structure (e.g.,
* rehash). This field is used to make iterators on Collection-views of
* the Hashtable fail-fast. (See ConcurrentModificationException).
*/
private transient int modCount = 0;

modCount 用来实现 fail-fast 机制…

这个属性在 Hashtable 很显眼,之前在 HashMap 没注意…

啥是 fail-fast 机制啊?

fail-fast 机制是 Java 集合的一种错误处理机制。下面这些类都有…

Map: HashMap、LinkedHash、MapTree、Map、Hashtable(线程安全)

Set: HashSet、LinkedHashSet、TreeSet

List: ArrayList、LinkedList、Vector(线程安全)

Collections.synchronizedXXX() 创建的线程安全的集合

具体是啥?

比如当多个线程对集合进行操作时,一个线程通过 itertor 遍历集合,而此刻另一个线程改变了集合的内容,这时迭代器会立马感知,立即抛出 ConcurrentModificationException 异常。

fail-fast 机制只能用于检测错误。

如何处理呢?

若在多线程环境下使用 fail-fast 机制的集合,建议使用 java.util.concurrent 包下的类去取代 java.util 包下的类。

搜索了一下,发现 modCount 几乎无处不在。put() 时会更新,clear() 时会更新…

查看源码,发现有这样的操作.

1
2
if (modCount != expectedModCount)
throw new ConcurrentModificationException();

不难想象,fail-fast 利用 modCount 来实现。

比如当一个线程对集合进行遍历,在此线程保持 expectedModCount =modCount。此时另一线程对集合进行 put() 操作,modCount++

判断 modCount != expectedModCount,立马抛出异常…

删除,插入元素都会影响 modCount。

这叫做「结构上的更改」…

PS:然而 set() 操作不会被视为「结构性的修改」。

loadDisqus