2015-10-12 2 views
1

У меня есть следующий последовательный код, который удаляет записи из хэш-карты, используя другой список ключей. Размер карты может составлять 50-100 тыс. Записей и удалить список ключей может быть 2k - 10k. Я ищу решения, используя новые Java-8 потоков ...ConcurrentHashMap с параллельными потоками для удаления ключей

List<Long> removed = new ArrayList<Long>(); 
    for (Long k : removelist) { 
     if (null != map.remove(k)) { 
      removed.add(k); 
     } 
    } 
+1

Поскольку «HashMap» не является потокобезопасным, любое многопоточное выполнение (потоки или другое) должно было бы блокировать карту для каждой операции, то есть не было бы никакой пользы. Использование «ConcurrentHashMap» позволяет избежать такой блокировки. – dimo414

ответ

5

Разновидность прямого перевода

List<Long> removed = removeList.parallelStream() 
     .map(key -> map.remove(key) != null ? key : null) 
     .filter(Objects::nonNull) 
     .collect(Collectors.toList()); 

на map шаг карты от ключа к ключу, если он может быть удален, чтобы null если не. null s затем фильтруют.

немного короче, непосредственно фильтрации для тех ключей, которые могут быть удалены:

List<Long> removed = removeList.parallelStream() 
     .filter(key -> map.remove(key) != null) 
     .collect(Collectors.toList()); 

или через remove метод набора ключей, который возвращает boolean и, следовательно, может быть использован непосредственно в качестве Predicate

List<Long> removed = removeList.parallelStream() 
      .filter(map.keySet()::remove) 
      .collect(Collectors.toList()); 
+4

Но вы всегда должны проверить, действительно ли это быстрее, чем обычный последовательный 'removeelist.retainAll (map.keySet()); map.keySet(). removeAll (removeelist); ' – Holger

+0

@Holger True. Хотя явный цикл 'for' OPs должен быть быстрее, чем этот однострочный, поскольку это всего лишь 1 итерация и, возможно, меньшая коллекция (в случае, если' keepAll' выполняет итерацию по полному набору ключей). Еще один момент для рассмотрения: параметр ['concurrencyLevel'] (http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#ConcurrentHashMap-int-float-int-) в конструкторе 'ConcurrentHashMap' – zapl

+3

' keepAll' никогда не выполняет итерацию по параметру, так как это не сработает. Так что в худшем случае это похоже на явный цикл, но, как правило, он может быстрее итерации и имеет меньшие накладные расходы, поскольку он работает на месте. Обратите внимание, что уровень параллелизма совершенно неактуальен в Java 8, поскольку «ConcurrentHashMap» работает не так, как в предыдущих версиях. Вот почему документ говорит: «* Реализация может использовать это значение в качестве подсказки для калибровки *». Теоретически, может быть столько же параллелизма, как и записи без коллизий. Вот почему я говорю: вы всегда должны проверять и сравнивать. Btw. Я предпочитаю ваш последний вариант. – Holger

Смежные вопросы