Параллелизм Java: равны ли по производительности get (Key) для HashMap и ConcurrentHashMap? - PullRequest
4 голосов
/ 29 января 2012

Являются ли get(Key) вызовы метода для стандартных HashMap и ConcurrentHashMap равными по производительности, когда не происходит никаких изменений для лежащей в основе карты (поэтому выполняются только операции get ().)

Обновление с фоном:

Параллелизм - довольно сложная тема: я занимаюсь "параллелизмом / безопасностью потоков", но только на путах, которые происходят крайне редко. А для путов я мог поменять карты самих ассоциаций (которые являются атомарными и многопоточными). Поэтому я спрашиваю, что я делаю много операций получения (и у меня есть возможность либо реализовать его с помощью HashMap (создать временную таблицу Hashmap, скопировать данные в новый HashMap и сопоставить своп), либо использовать ConcurrentHashMap ... Поскольку мое приложение действительно Я хочу узнать больше о том, как производительность теряется при разных способах. Как бы глупо это ни звучало, в Интернете так много ненужной информации, но я думаю, что это может заинтересовать гораздо больше людей. кто-то знает внутреннюю работу ConcurrentHashMap для получения, было бы здорово ответить на вопрос.

Большое спасибо!

Ответы [ 3 ]

3 голосов
/ 29 января 2012

Вы задаете неправильный вопрос.

Если вам нужен параллелизм, он вам нужен независимо от того, влияние на производительность.

Правильно работающая программа почти всегда занимает более высокое место, чем более быстрая программа.Я говорю «почти всегда», потому что могут быть деловые причины выпускать программное обеспечение с ошибками, а не сдерживать их до тех пор, пока ошибки не будут устранены.

2 голосов
/ 29 января 2012

Вы можете посмотреть на исходный код.(Я смотрю на JDK 6) HashMap.get () довольно прост:

public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }

Где hash () делает некоторые дополнительные смещения и XORing, чтобы «улучшить» ваш хэш-код.

ConcurrentHashMap.get () немного сложнее, но не намного

public V get(Object key) {
    int hash = hash(key.hashCode());
    return segmentFor(hash).get(key, hash);
}

Опять же, hash () выполняет некоторое смещение и XORing.setMentFor (int hash) выполняет простой поиск в массиве.Единственный сложный материал находится в Segment.get ().Но даже это не похоже на науку о ракетостроении:

V get(Object key, int hash) {
   if (count != 0) { // read-volatile
      HashEntry<K,V> e = getFirst(hash);
      while (e != null) {
         if (e.hash == hash && key.equals(e.key)) {
            V v = e.value;
            if (v != null)
               return v;
            return readValueUnderLock(e); // recheck
          }
          e = e.next;
      }
 }
  return null;
}

Единственное место, где можно получить блокировку, это readValueUnderLock ().В комментариях говорится, что это технически допустимо в модели памяти, но никогда не встречалось.

В целом, похоже, что код довольно похож для обоих.Чуть лучше организовано в ConcurrentHashMap.Поэтому я предполагаю, что производительность достаточно схожа.

Тем не менее, если путы действительно крайне редки, вы можете рассмотреть возможность реализации механизма типа «копирование при записи».

2 голосов
/ 29 января 2012

Согласно API ConcurrentHashMap блокировка для методов поиска отсутствует.Итак, я бы сказал, что они одинаковы по производительности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...