2015-09-01 4 views
1

У меня есть класс контейнер, содержащий коллекцию, которая будет использоваться несколькими потоками:Синхронизированная коллекция по сравнению с синхронизированным методом?

public class Container{ 

    private Map<String, String> map; 

    //ctor, other methods reading the map 

    public void doSomeWithMap(String key, String value){ 
     //do some threads safe action 
     map.put(key, value); 
     //do something else, also thread safe 
    } 
} 

Что было бы лучше, чтобы объявить метод synchronized:

public synchronized void doSomeWithMap(String key, String value) 

или использовать стандартную резьбу -сезонный декоратор?

Collections.synchronizedMap(map); 
+0

Если вам не нужно самостоятельно обрабатывать параллелизм, то чеча эту карту здесь http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html – AntJavaDev

+0

Ни то, Используйте [ConcurrentHashMap] (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html): – TheLostMind

+0

@ TheLostMind Не понятно, почему синхронизация метода неправильная ? –

ответ

2

Вообще говоря, синхронизация карты защитит самый доступ к ней, не задумываясь об этом дальше. Тем не менее, «синхронизированная карта» небезопасна для итерации, которая может быть проблемой в зависимости от вашего варианта использования. It is imperative that the user manually synchronize on the returned map when iterating over any of its collection views.

Рассмотрите возможность использования ConcurrentHashMap, если это встретит ваш прецедент.

Если в объекте есть другое состояние, которое необходимо защитить от ошибок параллелизма, вам потребуется использовать синхронизированный или Lock.

+1

Итак, основное отличие между [synxhronizedMap] (http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#synchronizedMap%28java.util.Map%29) состоит в том, что acces для чтения не синхронизируется, правильно? Таким образом, это дает нам накладные расходы на производительность по сравнению с concurrentHashMap ... –

+0

@ St.Antario 'ConcurrentHashMap' использует отдельные блокировки для групп хэш-бункеров, по умолчанию 16 я считаю. Это означает, что в целом меньше конфликтов блокировок, так как реализация может вычислить хэш ключа без конкуренции, а затем блокировать только 1/16 карты. ConcurrentHashMap также позволяет поточно-безопасную итерацию. –

1

Если другие вещи, которые вы делаете внутри doSomeWithMap, могут вызвать проблемы, если выполняются одновременно разными потоками (например, они обновляют переменные уровня класса), тогда вы должны синхронизировать весь метод. Если это не так, вы должны использовать синхронизированный Map, чтобы свести к минимуму время, в течение которого блокировка синхронизации остается на месте.

1

Если ваш метод doSomeWithMap будет иметь доступ к карте больше, чем когда-то, вы должны синхронизировать метод doSomeWithMap. Если доступ к только - это вызов put(), то лучше использовать ConcurrentHashMap.

Обратите внимание, что «более одного раза» - это любой вызов, и итератор по своей природе «получает».

1

Возможно, вам потребуется синхронизировать блок по требованию. Обратите внимание на это.

Когда вы используете синхронизированный Коллекцию как ConcurrentHashMap или метод сбора как synchronizedMap(), synchronizedList() и т.д., только Map/List синхронизируется. Чтобы объяснить немного дальше,

Рассмотрим,

Map<String, Object> map = new HashMap<>(); 
Map<String, Object> synchMap = Collections.synchronizedMap(map); 

Это делает МАП прибудете операция синхронными, а не объекты внутри него.

Object o = synchMap.get("1");// Object referenced by o is not synchronized. Only the map is. 

Если вы хотите защитить объекты внутри Карты, вам также необходимо поместить код внутри синхронизированного блока. Это хорошо помнить, поскольку многие люди забывают безопасно охранять объект в большинстве случаев.

Посмотрите на это для немного информации слишком Collection's synchronizedMap

1

Если посмотреть на реализации SynchronizedMap, вы увидите, что это просто карта обертывания нон поточно-карты, которая использует семафор перед вызовом любого метода

public V get(Object key) { 
    synchronized (mutex) {return m.get(key);} 
} 

public V put(K key, V value) { 
    synchronized (mutex) {return m.put(key, value);} 
} 

public Set<Map.Entry<K,V>> entrySet() { 
    synchronized (mutex) { 
    if (entrySet==null) 
     entrySet = new SynchronizedSet<>(m.entrySet(), mutex); 
    return entrySet; 
    } 
} 

Если все, что вы хотите, защищает get и put, эта реализация делает это для вас.

Однако это не подходит, если вы хотите, чтобы Карта, которую можно повторить и обновить двумя или более потоками, в этом случае вы должны использовать ConcurrentHashMap.

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