gpt4 book ai didi

Java ConcurrentHashMap 初始化

转载 作者:行者123 更新时间:2023-12-01 14:32:19 26 4
gpt4 key购买 nike

我目前正在阅读jdk1.8中ConcurrentHashMap的源代码,我发现initalTable()方法有点困惑。

public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable {
//some fields revolved in this method
transient volatile Node<K,V>[] table;
private transient volatile int sizeCtl;

private final Node<K,V>[] initTable() {
Node<K,V>[] tab; int sc;
while ((tab = table) == null || tab.length == 0) {
if ((sc = sizeCtl) < 0)
Thread.yield(); // lost initialization race; just spin
else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
try {
if ((tab = table) == null || tab.length == 0) {
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
@SuppressWarnings("unchecked")
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];//place 1
table = tab = nt;//place 2
sc = n - (n >>> 2);
}
} finally {
sizeCtl = sc;
}
break;
}
}
return tab;
}
}

所以主要的困惑主要集中在以下几点:

  1. 为什么我们需要 while((tab = table) == null || tab.length == 0) 来检查 table 是否为空及其长度不为0判断是否继续循环,所以只有当两个条件都为false时才退出。我只是想不出 table 不为 null 但长度为 0 的情况,因为它是在 else if block 中初始化的,其中 n 总是被赋予一个值大于 0。那为什么我们需要两者而不是一个?

<德尔>2。第二个问题不是问题,而是我只是想检查我的假设是否有意义。因此,想象一下两个线程随后以非常接近的方式运行。如果较早的线程尚未到达 table 或 place 2 的初始化点,也没有 sizeCtl,则较晚的线程可以进入 else if block 已经更新了,那么第二个线程就可以进入else if block ,所以table字段会被再次初始化?这种情况会在极少数情况下发生吗?我知道这不会影响程序的正确性,但它会在某些情况下发生吗?

希望有大佬指点一下。提前致谢。


更新:我忘记了一个成功的 CAS 操作会将 sizeCtl 交换为 -1 的事实,这将阻止其他线程进入 else if block ,但我仍然不清楚为什么我们在 ifwhile 中需要两个条件。

最佳答案

孤立地分析initTable方法是不够的。您需要考虑其他方法,这些方法也可以修改 tablesizeCtl 字段。在那里你会注意到,例如transfer 使用 CAS 将 sizeCtl 减一。我不确定这是否会在任何时间点导致 table.length == 0,但请注意,整个过程要复杂得多,initTable 可以与调整大小操作同时调用。

关于Java ConcurrentHashMap 初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61722136/

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