Сложность метода Concurrent hashmap size()
Мне интересно, имеет ли метод size()
, вызываемый на ConcurrentHashMap
, ту же сложность, что и метод size()
для обычной хэш-карты.
5 ответов:
Это не так. в моей версии JDK,
HashMap.size()
имеетO(1)
сложность, тогда какConcurrentHashMap.size()
в лучшем случае приходится перебирать отрезки. В худшем случае он заблокирует все сегменты, что может быть довольно дорогостоящей операцией в многопоточном сценарии.Конечно, что быстрее - это совсем другой вопрос. Ответ во многом зависит от того, сколько потоков получают доступ к карте и что именно они делают.
Новая реализация ConcurrentHashMap.size () в JDK 8 использует классный алгоритм, который они вроде как копируют, вставленные из LongAdder.
В сущности, сложность
ConcurrentHashMap.size()
почти постоянна ("O(1)" на языке ботаников), а затраты реального времени по сравнению сHashMap.size()
ничтожны. Не веришь мне? Откройте Мой базовый тестовый проект и запустите его самостоятельно. У меня нет JDK 7, установленного на моей текущей машине, было бы здорово получить обратную связь по стоимости времени с Java 1.7 по сравнению с Java 1.8.
Сложность
size()
наHashMap
равнаO(1)
, поскольку размер хранится в поле. Если мы посмотрим на реализациюsize()
наConcurrentHashMap
, то увидим, что она больше (>O(1))Ссылка (openjdk-6)
Сложность метода size() в ConcurrentHashMap по существу является операцией O(N) (изменяющейся в основном с количеством сегментов), как вы можете видеть в источнике. HashMap-это операция O (1).
/** * Returns the number of key-value mappings in this map. If the * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns * <tt>Integer.MAX_VALUE</tt>. * * @return the number of key-value mappings in this map */ public int size() { final Segment<K,V>[] segments = this.segments; long sum = 0; long check = 0; int[] mc = new int[segments.length]; // Try a few times to get accurate count. On failure due to // continuous async changes in table, resort to locking. for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { check = 0; sum = 0; int mcsum = 0; for (int i = 0; i < segments.length; ++i) { sum += segments[i].count; mcsum += mc[i] = segments[i].modCount; } if (mcsum != 0) { for (int i = 0; i < segments.length; ++i) { check += segments[i].count; if (mc[i] != segments[i].modCount) { check = -1; // force retry break; } } } if (check == sum) break; } if (check != sum) { // Resort to locking all segments sum = 0; for (int i = 0; i < segments.length; ++i) segments[i].lock(); for (int i = 0; i < segments.length; ++i) sum += segments[i].count; for (int i = 0; i < segments.length; ++i) segments[i].unlock(); } if (sum > Integer.MAX_VALUE) return Integer.MAX_VALUE; else return (int)sum; }
Это неуместный вопрос, поскольку вызов функции size() для одновременно изменяемой структуры является по существу бессмысленным. Все, что он когда-либо скажет вам, это то, что размер был, и вы не можете ничего сделать с этой информацией, кроме, возможно, протоколировать ее.
Если вы попытаетесь использовать функцию size () без блокировки структуры, у вас будут условия гонки.