#java #java.util.concurrent
#java #java.util.concurrent
Вопрос:
В методе addCount (также в методе helpTransfer) первым условием для остановки расширения емкости является (sc >>> RESIZE_STAMP_SHIFT) != rs
, я знаю, что здесь есть ошибка в JDK8:вероятная ошибка в логике ConcurrentHashMap.addCount().Но в JDK12 мне интересно: почему это условие (sc >>> RESIZE_STAMP_SHIFT) != rs
было удалено? Я думаю, что это условие должно стать (sc >>> RESIZE_STAMP_SHIFT) != (rs >>> RESIZE_STAMP_SHIFT)
в JDK12.
В JDK8:
private final void addCount(long x, int check) {
//...
if (check >= 0) {
Node<K,V>[] tab, nt; int n, sc;
while (s >= (long)(sc = sizeCtl) amp;amp; (tab = table) != null amp;amp;
(n = tab.length) < MAXIMUM_CAPACITY) {
int rs = resizeStamp(n);
if (sc < 0) {
if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs 1 ||
sc == rs MAX_RESIZERS || (nt = nextTable) == null ||
transferIndex <= 0)
break;
//...
}
//...
}
}
}
В JDK12:
private final void addCount(long x, int check) {
//...
if (check >= 0) {
Node<K,V>[] tab, nt;
int n, sc;
while (s >= (long)(sc = sizeCtl) amp;amp; (tab = table) != null amp;amp;
(n = tab.length) < MAXIMUM_CAPACITY) {
int rs = resizeStamp(n) << RESIZE_STAMP_SHIFT;
if (sc < 0) {
if (sc == rs MAX_RESIZERS || sc == rs 1 ||
(nt = nextTable) == null || transferIndex <= 0)
break;
//...
}
//...
}
}
}
Я также заметил проблему с ошибкой в логике ConcurrentHashMap.addCount() при использовании в потоках, но он все еще находится в открытом состоянии
Ответ №1:
(sc >>> RESIZE_STAMP_SHIFT) != rs
означает, что tab.length
изменено после назначения ( sc = sizeCtl
). В этой ситуации должен быть завершен другой поток или завершается изменение размера (в методе переноса).
-
Когда оно завершится,
nextTable == null
будетtrue
. -
Когда оно будет завершено,
sizeCtl
оно будет отличаться от текущего для разныхsizeCtl
этапов изменения размера.
Тогда ( U.compareAndSetInt(this, SIZECTL, sc, sc 1)
) будет равно false, и этот поток на следующей итерации прервет while для sc > 0
или поможет при следующем изменении размера или повторной попытке.
private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
...
if (finishing) {
nextTable = null;
// table changed after "nextTable = null"。
table = nextTab;
sizeCtl = (n << 1) - (n >>> 1);
return;
}
...
}