Java 并发hashmap size()方法复杂性
我想知道在Java 并发hashmap size()方法复杂性,java,concurrency,java.util.concurrent,concurrenthashmap,Java,Concurrency,Java.util.concurrent,Concurrenthashmap,我想知道在ConcurrentHashMap上调用的size()方法是否与普通HashMap的size()方法具有相同的复杂性 不是。在我的JDK版本中,HashMap.size()具有O(1)复杂性,而ConcurrentHashMap.size()在最好的情况下必须迭代段。在最坏的情况下,它将锁定所有段,这在多线程场景中可能是一个非常昂贵的操作 当然,哪个更快是完全不同的问题。答案很大程度上取决于有多少线程正在访问映射,以及它们到底在做什么。HashMap上的size()的复杂性是O(1),
ConcurrentHashMap
上调用的size()
方法是否与普通HashMap的size()
方法具有相同的复杂性 不是。在我的JDK版本中,HashMap.size()
具有O(1)
复杂性,而ConcurrentHashMap.size()
在最好的情况下必须迭代段。在最坏的情况下,它将锁定所有段,这在多线程场景中可能是一个非常昂贵的操作
当然,哪个更快是完全不同的问题。答案很大程度上取决于有多少线程正在访问映射,以及它们到底在做什么。HashMap上的
size()
的复杂性是O(1)
,因为大小存储在字段中。如果我们看一下ConcurrentHashMap
上size()
的实现,就会发现它更大(>O(1))
参考(openjdk-6)
/**
* Returns the number of key-value mappings in this map. If the
* map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
* <tt>Integer.MAX_VALUE</tt>.
*
* @return the number of key-value mappings in this map
*/
public int size() {
final Segment<K,V>[] segments = this.segments;
long sum = 0;
long check = 0;
int[] mc = new int[segments.length];
// Try a few times to get accurate count. On failure due to
// continuous async changes in table, resort to locking.
for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
check = 0;
sum = 0;
int mcsum = 0;
for (int i = 0; i < segments.length; ++i) {
sum += segments[i].count;
mcsum += mc[i] = segments[i].modCount;
}
if (mcsum != 0) {
for (int i = 0; i < segments.length; ++i) {
check += segments[i].count;
if (mc[i] != segments[i].modCount) {
check = -1; // force retry
break;
}
}
}
if (check == sum)
break;
}
if (check != sum) { // Resort to locking all segments
sum = 0;
for (int i = 0; i < segments.length; ++i)
segments[i].lock();
for (int i = 0; i < segments.length; ++i)
sum += segments[i].count;
for (int i = 0; i < segments.length; ++i)
segments[i].unlock();
}
if (sum > Integer.MAX_VALUE)
return Integer.MAX_VALUE;
else
return (int)sum;
}
/**
*返回此映射中的键值映射数。如果
*映射包含多个Integer.MAX\u值元素,返回
*Integer.MAX_值。
*
*@返回此映射中的键值映射数
*/
公共整数大小(){
最终段[]段=本段;
长和=0;
长检查=0;
int[]mc=新的int[segments.length];
//尝试几次以获得准确的计数。由于
//表中的连续异步更改,求助于锁定。
for(int k=0;k<锁定前重试;++k){
检查=0;
总和=0;
int mcsum=0;
对于(int i=0;i整数最大值)
返回Integer.MAX_值;
其他的
返回(整数)和;
}
这是一个无关紧要的问题,因为在并发可变结构上调用size()实际上是一件毫无意义的事情。它所能告诉你的只是它的大小,除了记录它之外,你不能用这些信息做任何事情
如果您尝试在不锁定结构的情况下使用size(),您将遇到竞争条件。JDK 8的新实现使用了一种很酷的算法,这种算法类似于复制粘贴
实际上,
ConcurrentHashMap.size()
的复杂性几乎是恒定的(在nerd语言中是“O(1)”),与HashMap.size()相比,实时成本可以忽略不计。不相信我?打开我的basic,自己跑步。我当前的机器上没有安装JDK 7,与Java 1.8相比,使用Java 1.7获得关于时间成本的反馈会很酷。有趣的发现,Martin!我发现在JDK 8中,这不再是事实。请在本页(或)的其他地方查看我的答案。这并没有真正的帮助。您是否可以删除较长的源代码片段,并告诉我们为什么映射被拆分为多个段,以及我们希望找到多少段?只有当分段数为N的常数分数时,我们才能得到O(N)复杂度。