与Hashtable比较get方法和clear方法

2021-10-08 15:04:01 浏览数 (1)

与Hashtable比较

  由于Hashtable无论是读还是写还是遍历,都需要获得对象锁,串行操作,因此在多线程环境下性能比较差。   但是ConcurrentHashMap不能完全取代Hashtable:HashTable的迭代器是强一致性的,而ConcurrentHashMap是弱一致的。其实 ConcurrentHashMap的get,clear,iterator 都是弱一致性的。 Doug Lea 也将这个判断留给用户自己决定是否使用ConcurrentHashMap。   弱一致性:不保证数据完全处于一致性状态。比如:

get方法:

可能在get的时候获得一个还没完全构造好的HashEntry对象,导致获得的entry的value为null,此时需要加锁重新读取。

clear方法
代码语言:javascript复制
public void clear() {
	for (int i = 0; i < segments.length;   i)
		segments[i].clear();
}

  因为没有全局的锁,在清除完一个segments之后,正在清理下一个segments的时候,已经清理segments可能又被加入了数据,因此clear返回的时候,ConcurrentHashMap中是可能存在数据的。因此,clear方法是弱一致的。

迭代器

   java.util 包中的集合类都返回 fail-fast 迭代器,这意味着它们假设线程在集合内容中进行迭代时,集合不会更改它的内容。如果 fail-fast 迭代器检测到在迭代过程中进行了更改操作,那么它会抛出 ConcurrentModificationException。    ConcurrentHashMap中的迭代器主要包括entrySet、keySet、values方法。它们大同小异,这里选择entrySet解释。当我们调用entrySet返回值的iterator方法时,返回的是EntryIterator,在EntryIterator上调用next方法时,最终实际调用到了HashIterator.advance()方法,看下这个方法:

代码语言:javascript复制
final void advance() {
    if (nextEntry != null && (nextEntry = nextEntry.next) != null)
        return;
 
    while (nextTableIndex >= 0) {
        if ( (nextEntry = currentTable[nextTableIndex--]) != null)
            return;
    }
 
    while (nextSegmentIndex >= 0) {
        Segment<K,V> seg = segments[nextSegmentIndex--];
        if (seg.count != 0) {
            currentTable = seg.table;
            for (int j = currentTable.length - 1; j >= 0; --j) {
                if ( (nextEntry = currentTable[j]) != null) {
                    nextTableIndex = j - 1;
                    return;
                }
            }
        }
    }
}

  在这种迭代方式中,比如我们删除了链表的某个entry,但是在完成之前,迭代器获得了旧的链表指针,那么就会遍历旧的链表,并且不会报异常。

0 人点赞