gpt4 book ai didi

java - HashMap 和可见性

转载 作者:搜寻专家 更新时间:2023-10-30 19:42:34 25 4
gpt4 key购买 nike

HashMap's javadoc状态:

if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException.

我构建了一个示例代码,根据规范,它应该几乎立即失败并抛出 ConcurrentModificationException;

  • 它确实像 Java 7 预期的那样立即失败
  • 但它(似乎)总是与 Java 6 一起工作(即它不会抛出 promise 的异常)。

注意:Java 7 有时不会失败(比如 20 次中有 1 次)——我猜这与线程调度有关(即 2 个可运行对象没有交错)。

我错过了什么吗?为什么运行 Java 6 的版本不抛出 ConcurrentModificationException?

实质上,有 2 个 Runnable 任务并行运行(使用倒计时锁存器使它们大致同时开始):

  • 一个正在向 map 添加项目
  • 另一个正在遍历 map ,读取键并将它们放入数组

然后主线程检查有多少键被添加到数组中。

Java 7 典型输出(迭代立即失败):

java.util.ConcurrentModificationException
MAX i = 0

Java 6 典型输出(整个迭代过程,数组包含所有添加的键):

MAX i = 99

使用的代码:

public class Test1 {

public static void main(String[] args) throws InterruptedException {
final int SIZE = 100;
final Map<Integer, Integer> map = new HashMap<Integer, Integer>();
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
final int[] list = new int[SIZE];
final CountDownLatch start = new CountDownLatch(1);
Runnable put = new Runnable() {
@Override
public void run() {
try {
start.await();
for (int i = 4; i < SIZE; i++) {
map.put(i, i);
}
} catch (Exception ex) {
}
}
};

Runnable iterate = new Runnable() {
@Override
public void run() {
try {
start.await();
int i = 0;
for (Map.Entry<Integer, Integer> e : map.entrySet()) {
list[i++] = e.getKey();
Thread.sleep(1);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
ExecutorService e = Executors.newFixedThreadPool(2);
e.submit(put);
e.submit(iterate);
e.shutdown();

start.countDown();
Thread.sleep(100);
for (int i = 0; i < SIZE; i++) {
if (list[i] == 0) {
System.out.println("MAX i = " + i);
break;
}
}
}
}

注意:在 x86 机器上使用 JDK 7u11 和 JDK 6u38(64 位版本)。

最佳答案

如果我们查看 HashMap 源代码并将它们与 Java 6 和 Java 7 进行比较,我们将看到如此有趣的差异:

transient volatile int modCount; 在 Java6 中只是 transient int modCount; 在 Java7 中。

我确定这是导致上述代码出现不同行为的原因:

        if (modCount != expectedModCount)
throw new ConcurrentModificationException();

UPD: 在我看来,这是一个已知的 Java 6/7 错误:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6625725已在最新的 Java7 中修复。

UPD-2:@Renjith 先生说,他刚刚进行了测试,没有发现 HashMaps 实现的行为有任何差异。但我也刚测试过。

我的测试是:

1) 我已经创建了 HashMap2 类,它完全是HashMap 来自 Java 6 的副本。

重要的是我们需要在这里引入 2 个新字段:

transient volatile Set<K>        keySet = null;

transient volatile Collection<V> values = null;

2) 然后我用这个HashMap2来测试这个问题,并在Java 7下运行它

结果:它在 Java 6 下像这样的测试一样工作,即没有任何 ConcurentModificationException

这一切都证明了我的猜想。 Q.E.D.

关于java - HashMap 和可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14363123/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com