我试图通过分配线程仅修改它们各自的节点来规避HashMap中的并发Node
冲突。但是,预期的尺寸结果仍然不准确。
我知道HashMap不能并发,因为不同的线程会修改同一链接列表。 #hashSlot
用于计算HashMap插入的节点。
这是我的例子:
public class Maptest {
private static HashMap map = new HashMap(1024,1);
public static void main(String[] args) throws InterruptedException {
Thread writeThread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
int a = hashSlot(String.valueOf(i));
if (a >= 500) {
map.put(String.valueOf(i), i);
}
}
}
});
writeThread.start();
for (int i = 0; i < 1000; i++) {
int a = hashSlot(String.valueOf(i));
if (a < 500) {
map.put(String.valueOf(i), i);
}
}
writeThread.join();
System.out.println(map.size());
}
public static int hashSlot(String i) {
int h;
int b = (h = i.hashCode()) ^ (h >>> 16);
return 1023 & b;
}
}
结果是带有size() != 1000
的映射,但是没有一个哈希码在同一线程内发生冲突。为什么最终尺寸不是1000?
答案 0 :(得分:0)
关于您当前测试用例的一些要点:
map.entrySet().stream().count()
的值是否会返回999或1000,具体取决于是否满足比赛条件。现在,在回答有关size
的特定问题时:
//HashMap#putVal (near method end)
if (++size > threshold) //both are fields
resize();
threshold
是大小限制,直到调用下一个#resize操作为止,在您的情况下,该操作被设置为initialCapacity
参数:1024。在测试用例中,您永远都不会遇到这个问题。 / p>
然而,size
只是#put方法末尾的一个预增量,如果在地图上添加新值,它将始终被调用。这绝对是线程不安全的,但总体上不会对地图存储和检索结果的功能产生重大影响。就是说,不要指望size
在这里确实能提供很好的价值,同时修改的地方越多,它就会变得越糟。真正的缺点是它会放弃地图调整大小的计算,从而降低性能。