ConcurrentHashMap1.7 и 1,8 контраст

https://medium.com/@itsromiljain/curious-case-of-concurrenthashmap-90249632d335    этот концептуальный разговор о том , 1,7

https://crossoverjie.top/2018/07/23/java-senior/ConcurrentHashMap/  анализ и сравнение хорошего письма

 

Специальный код, чтобы увидеть JDK

1,7

/ * * 
 * Массив сегментов, при сохранении данных первым нужно найти конкретный сегмент. 
 * / 
Окончательный Сегмент <K, V> [] Сегменты; при 
переходных процессах в Set <K> Keyset; 
переходная Набор <из Map.Entry <K, V >> в entrySet;

Сегмент представляет собой внутренний класс

   статический Заключительный класс Сегмент <K, V> расширяет орудия ReentrantLock сериализуемого {
        Private  статического Final Long serialVersionUID = 2249069246763182397L ; 
       
       // и HashEntry роль в HashMap, реальные данные , хранящихся ванночка 
       переходного летучий HashEntry <K, V> [] Таблица; 
       переходный INT COUNT; 
       переходная INT ModCount, 
       переходная INT порог, 
       Final поплавок loadFactor; 
       
}

HashEnrty

    статического окончательного класса HashEnrty <K, V> { 
        окончательного Int хэш; 
        Окончательный ключ K; 
        летучее значение V;
        летучее HashEnrty <K, V> следующая; 
    }

 

 

 

 

1.ConcurrentHashMap получит блокировку повторного входа для обеспечения целостности данных, сам сегмент основан на расширении ReentrantLock достижения, поэтому при одновременной модификации, соответствующий сегмент заблокирован.

2. На начальном этапе, повторные сканирования, чтобы определить, является ли соответствующий ключевое значение в массиве уже внутри, а затем решить, следует ли обновить или введен в эксплуатацию, вы можете увидеть соответствующие комментарии в коде. Повторить сканирование, обнаружение конфликтов является общей методикой ConcurrentHashMap.

3. Это не общее поведение расширения, но отдельно Сегмент для расширения

 

1,8

 

Он отказался от оригинального замка сегмента сегмента, в то время как использование  CAS + synchronized для обеспечения безопасности параллелизма.

 

 

Окончательный V putVal (ключ K, V значение, логическое onlyIfAbsent) {
         если (ключ == NULL || значение == NULL ) бросить  новый NullPointerException ();
        INT хэш = спрэд (key.hashCode ());
        INT binCount = 0 ;
        для (узел <K, V> [] = вкладка таблицы ;;) { 
            Узел <K, V> F; INT N, I, СПЧ; К Fk; В бс;
            если (вкладка == NULL || (п = tab.length) == 0 ) //判断是否需要初始化
                вкладка = initTable ();
            остальное ,  если ((е = Табат (закладка, I = (N - 1) & хэш)) == NULL ) {//进行数据写
                 если (casTabAt (закладка, I, нулевое , новый узел <K, V> (хэш , ключ, значение)))
                     перерыв ;                   // нет блокировки при добавлении в пустой бункер 
            }
             еще  если ((Fh = f.hash) == Перенесено) //扩容
                вкладка = helpTransfer (вкладка, е);
            еще  если (onlyIfAbsent // проверить первый узел без получения блокировки 
                     && СПЧ ==Хэш
                      && ((Ф.К. = f.key) == ключ || (Ф.К.! = NULL && key.equals (Ф.К.)))
                      && (бс = f.val)! = NULL )
                 возвращение бс;
            еще { 
                V oldVal = NULL ;
                синхронизированы (е) {//为了确保能写入,锁
                     , если (Табат (закладка, я) == е) {
                         если (СПЧ> = 0 ) { 
                            binCount = 1 ;
                            для (узел <K, V> е = е ;; ++ binCount) {
                                К ек; 
                                если (e.hash == хэш && 
                                    ((ек = e.key) == ключ || 
                                     (ек =! нуль && key.equals (ек)))) { 
                                    oldVal = e.val;
                                    если (! onlyIfAbsent) 
                                        e.val = значение;
                                    перерыв ; 
                                } 
                                Узел <K, V> PRED = е;
                                если((е = e.next) == NULL ) { 
                                    pred.next = новый узел <K, V> (хэш, ключ, значение);
                                    перерыв ; 
                                } 
                            } 
                        } 
                        Еще ,  еслиInstanceOf TreeBin) { 
                            Узел <K, V> р; 
                            binCount = 2 ;
                            если ((р = ((TreeBin <K, V>  ) е) .putTreeVal (хэш, ключ,
                                                           значение)) ! = NULL) { 
                                OldVal = p.val;
                                если (! onlyIfAbsent) 
                                    p.val = значение; 
                            } 
                        } 
                        Еще  еслиInstanceOf ReservationNode)
                             бросить  новый IllegalStateException ( "Рекурсивный обновление" ); 
                    } 
                } 
                Если (binCount! = 0 ) {
                     если (binCount> = TREEIFY_THRESHOLD)
                        treeifyBin (закладка, я); //转换红黑树
                    если (oldVal! = NULL )
                         вернуть oldVal;
                    перерыв ; 
                } 
            } 
        } 
        AddCount ( 1L , binCount);
        возвращать  нуль ; 
    }

 

1. Это не общее поведение расширения, но отдельно Сегмент для расширения

2. потому что они больше не использовать сегмент, операция инициализации значительно упрощаются, модифицированы для формы отложенной нагрузки, которая может эффективно избежать первоначальных накладные расходов решить эту старую версию много людей жалуется.

3. Использование энергонезависимого хранения данных для обеспечения видимости.

4. КАС и другие операции, выполняемые в конкретном сценарии операции блокировки одновременно.

5. небезопасный, LongAdder как нижние средства, оптимизирующих экстремальных ситуаций.

 

Он использует синхронизируется, а не обычный рекомендуемый ReentrantLock как, почему? В современной версии JDK, синхронизируются постоянно оптимизируется, не слишком беспокоиться о разнице в производительности, кроме того, по сравнению с ReentrantLock, что снижает потребление памяти, это очень большое преимущество.

рекомендация

отwww.cnblogs.com/CherryTab/p/12169045.html