在java并发hashmap中clear的默认行为是什么

时间:2018-05-12 00:49:16

标签: java concurrenthashmap

在内部是否会锁定所有行并标记要删除的每个键?因此,如果另一个线程想要访问即将被删除的密钥,它将提供正确的行为吗?

或者我们是否必须同步清除功能

synchronized (this) {
    myMap.clear();
}

例如,请考虑以下内容

myMap = {1: 1, 2: 1, 3: 1}

//Thread1
myMap.clear()
//Thread2
myMap.compute(1, (k, v) -> {v == null ? 0 : k + 1})

当thread1首先执行而thread2想要访问key1但key1尚未删除时会发生什么?

结果是

{}

{1: 0}

1 个答案:

答案 0 :(得分:2)

该上下文中clear()的行为未指定 1 javadoc州:

  

“对于诸如putAll和clear之类的聚合操作,并发检索可能反映只插入或删除一些条目。”

查看源代码,clear()是通过一次清除每个段来实现的。清除时每个段都被锁定,但整个地图上没有锁定。这意味着另一个线程可能会在整个clear()调用返回之前向刚刚清除的段添加条目。

因此,在实践中,您提出的结果/行为中的任何一个都是可能的,这取决于地图的大小,段之间的键的分布,您正在使用的Java的版本以及......时间。

  

在内部是否会锁定所有行并标记要删除的每个键?

没有。每个段都被锁定(一次一个),而段中的条目被删除。 (这样做是为了避免可能破坏段的哈希链等的内存异常)

关于这个:

synchronized (this) {
    myMap.clear();
}

clear()正在进行时,这不会阻止其他线程插入元素。它将同时停止两个线程(执行相同的代码)。

如果您想保证clear()清除地图,您需要使用Collections.synchronizedMap包装器包装地图,并始终如一地使用它。在实践中,这违背了使用ConcurrentHashMap的目的。

后续问题:

  

因此可能存在无限循环的清算权?如果另一个线程继续添加元素,则地图的大小始终是> 0,尝试清除的线程将继续运行。

不。没有无限循环。 clear()方法不会查看地图的大小。

实际发生的是clear()调用将返回,地图不一定是空的。

1 - 仔细阅读后,我意识到引用的javadoc没有直接回答这个问题。事实上,如果您查看Map.clear() javadoc中的“合同”,它会在那里表明在调用返回后地图将为空。这与ConcurrentHashMap.clear() javadoc的javadoc隐含地相矛盾,并且明显与代码实际上的内容相矛盾。