изменение ConcurrentHashMap и Synchronized ArrayList в одном методе - PullRequest
2 голосов
/ 28 июля 2011

У меня есть коллекция объектов, которая изменяется одним потоком и читается другим (точнее, EDT).Мне нужно было решение, которое дало бы мне быстрый поиск, а также быструю индексацию (в порядке вставки), поэтому я использую ConcurrentHashMap с сопровождающим ArrayList ключей, поэтому, если вы хотите проиндексировать запись, я могу проиндексировать список дляключ, а затем используйте возвращенный ключ, чтобы получить значение из хэш-карты.Итак, у меня есть класс-обертка, который гарантирует, что при добавлении записи добавляется отображение в хэш-карту и ключ добавляется в список одновременно, аналогично для удаления.

Я публикуюПример кода, о котором идет речь:

private List<K> keys = Collections.synchronizedList(new ArrayList<K>(INITIAL_CAPACITY));

private ConcurrentMap<K, T> entries = new ConcurrentHashMap<K, T>(INITIAL_CAPACITY, .75f);

public synchronized T getEntryAt(int index){
     return entries.get(keys.get(index));
}

**public synchronized void addOrReplaceEntry(K key, T value){
     T result = entries.get(key);
     if(result == null){
         entries.putIfAbsent(key, value);
         keys.add(key);
     }
     else{
         entries.replace(key, result);
     }
}**

public syncrhonized T removeEntry(K key, T value){
     keys.remove(key);
     entries.remove(key, value);
}

public synchronized int getSize(){
     return keys.size();
}

Мой вопрос таков: теряю ли я все преимущества использования ConcurrentHashMap (по сравнению с syncrhonized hashmap), работая с ним синхронизированными методами?Я должен синхронизировать методы для безопасного изменения / чтения из ArrayList ключей (CopyOnWriteArrayList не вариант, потому что много изменений происходит ...) Кроме того, если вы знаете лучший способ сделать это, это будет оценено...

Ответы [ 5 ]

0 голосов
/ 28 июля 2011

Вы можете получить полный доступ к списку keys в очередь событий, используя EventQueue.invokeLater.Это избавит от синхронизации.При всей синхронизации вы все равно не работали параллельно.Также это означает, что метод getSize даст тот же ответ на время события.

Если вы используете синхронизацию вместо invokeLater, по крайней мере, получите хэш-таблицу entries изблок синхронизации.В любом случае вы получаете больше параллельной обработки.Конечно, entries теперь может стать не синхронизированным с keys.Единственным недостатком является то, что иногда ключ дает нулевую запись.С такой динамической таблицей это вряд ли будет иметь большое значение.

Использование предложения, сделанного chrisichris для помещения значений в список, решит эту проблему, если она таковая.Фактически, это создает хорошую стену между keys и entries;теперь они используются совершенно разными способами.(Если вам нужно только entries предоставить значения для JTable, вы можете от него избавиться.) Но entries (если все еще необходимо) должен ссылаться на записи, а не содержать индекс;поддержание индексов было бы безнадежной задачей.И всегда помните, что keys и entries - это снимки "реальности" (из-за отсутствия лучшего слова), сделанные в разное время.

0 голосов
/ 28 июля 2011

Почему бы не сохранить значения в списке и на карте ключ -> отображение индекса?

так что для getEntry вам нужно только при поиске (в списке, который должен быть в любом случае быстрее, чем на карте), а при удалении вам не нужно обходить весь список. Синхронизация происходит так.

0 голосов
/ 28 июля 2011

Похоже, вы заботитесь только о поиске значений по индексу. Если это так, сбросьте карту и просто используйте список. Зачем вам карта?

0 голосов
/ 28 июля 2011

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

0 голосов
/ 28 июля 2011

Да, использование параллельной коллекции и синхронизированной коллекции только в синхронизированных блоках является пустой тратой. Вы не получите преимуществ ConcurrentHashMap, потому что только один поток будет получать к нему доступ одновременно.

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

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

Я не совсем уверен в полезности проверки метода удаления по индексу, возможно, вы могли бы рассказать подробнее о проблеме, которую вы пытаетесь решить?

...