ConcurrentHashMap能完全替代HashTable吗

我们知道ConcurrentHashMap和HashTable都是线程安全的HashMap,其中ConcurrentHashMap在性能方面也是完全优于HashTable,那么ConcurrentHashMap可以完全替代HashTable吗?(对于JDK1.6、1.7)

答案是不能,HashTable的迭代器是强一致性的,而ConcurrentHashMap是弱一致性的。ConcurrentHashMap的get、clear、iterator都是弱一致性的。

什么是弱一致性和强一致性?

get方法是弱一致性的,就是你期望往ConcurrentHashMap中加入一个元素后,立马能对get可见,但ConcurrentHashMap并不能如你所愿。put操作将一个元素加入到ConcurrentHashMap后,get可能在某段时间内还不能看到这个元素。

V put(K key, int hash, V value, boolean onlyIfAbsent) {
	lock();
	try {
		int c = count;
		if (c++ > threshold) // ensure capacity
			rehash();
		HashEntry[] tab = table;
		int index = hash & (tab.length - 1);
		HashEntry first = tab[index];
		HashEntry e = first;
		while (e != null && (e.hash != hash || !key.equals(e.key)))
			e = e.next;

		V oldValue;
		if (e != null) {
			oldValue = e.value;
			if (!onlyIfAbsent)
				e.value = value;
		}
		else {
			oldValue = null;
			++modCount;
			tab[index] = new HashEntry(key, hash, first, value); // 1
			count = c; // write-volatile  2
		}
		return oldValue;
	} finally {
		unlock();
	}
}
V get(Object key, int hash) {
	if (count != 0) { // read-volatile 3
		HashEntry e = getFirst(hash); //4
		while (e != null) {
			if (e.hash == hash && key.equals(e.key)) {
				V v = e.value;
				if (v != null)
					return v;
				return readValueUnderLock(e); // recheck
			}
			e = e.next;
		}
	}
	return null;
}

我们可以核心关注上面代码块中的【1,2】和【3,4】语句,其中【1,2】为put元素,【3,4】为get元素,其中put时加了锁,而get没有加锁,当发生下面这种运行顺序的时候,就可能导致get不能立即看到put所进行的操作。

执行put的线程 执行get的线程
⑧tab[index] = new HashEntry<K,V>(key, hash, first, value)  
  ③if (count != 0)
②count = c  
  ⑨HashEntry e = getFirst(hash);

我们通过分析,发现可能存在已将数据put进数组,但put中count还未写入,get中count已被读取,那么可能就会导致get中读取不到刚才已经被put进的数据。还有getFirst(hash)先执行,tab[index] = new HashEntry<K,V>(key, hash, first, value)后执行,那么这个get操作也是看不到put的操作的。

发生这种现象的根本原因是get操作几乎是一个无锁的操作,使得同一个Segment上的get和put可以同时进行,这是get是弱一致性的根本原因。

public void clear() {
	for (int i = 0; i < segments.length; ++i)
		segments[i].clear();
}

clear方法中,因为没有全局的锁,就可能会导致在清理完一个Segment后,清理下一个Segment的时候,已经被清理的Segment可能又会被加入数据,这就会导致clear返回的时候,ConcurrentHashMap中存在数据。这就是clear方法弱一致性的原因。

ConcurrentHashMap的弱一致性主要是为了提高效率,是一致性和效率上的一种均衡,如果要实现强一致性,就可能到处加锁甚至全局锁,那就和HashTable基本一样了。

参考:https://my.oschina.net/hosee/blog/675423

猜你喜欢

转载自blog.csdn.net/weixin_42294335/article/details/81202571
今日推荐