Почему это условие «(sc >>> RESIZE_STAMP_SHIFT) != rs» было удалено в JDK12 ConcurrentHashMap?

#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 ). В этой ситуации должен быть завершен другой поток или завершается изменение размера (в методе переноса).

  1. Когда оно завершится, nextTable == null будет true .

  2. Когда оно будет завершено, 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;
    }
...
}