Treemap внутри ConcurrentHashMap поток безопасно?

1

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

private final static Map<String, TreeMap<Long,String>> outerConcurrentMap = new ConcurrentHashMap<>();

Я знаю, что ConcurrentHashMap является потокобезопасным, но я хочу знать о TreeMap этой CHM-холдинге, они также потокобезопасны внутри CHM?

Операции, которые я выполняю:

  1. Если конкретный ключ не найден → создайте новый TreeMap и поставьте против ключа.
  2. Если ключ найден, получите TreeMap и обновите его.
  3. Извлеките TreeMap из CHM, используя get(K).
  4. Извлеките данные из TreeMap с помощью tailMap(K,boolean).
  5. clear() CHM.

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

Теги:
thread-safety
treemap
concurrency
concurrenthashmap

5 ответов

4
Лучший ответ

После того, как вы сделали TreeMap<?,?> tm = chm.get(key); вы больше не находитесь в нитебезопасной территории. В частности, если другой поток обновляет treemap (через CHM или нет), вы можете увидеть или не увидеть изменение. Хуже того, копия карты, которую вы имеете в tm может быть повреждена...

Один из вариантов - использовать безопасную по потоку карту, такую как ConcurrentSkipListMap.

  • 0
    Но вам придется как-то защитить операцию копирования ...
  • 0
    @ Хольгер дух ... спасибо ...
2

Простой ответ: нет.

Если ваша карта является ConcurrentHashMap, все операции, влияющие на состояние вашего хэшмапа, являются потокобезопасными. Это вовсе не означает, что объекты, хранящиеся на этой карте, становятся потокобезопасными.

Как это будет работать; вы создаете какой-либо объект и, добавляя его к такой карте, сам объект становится потокобезопасным? И когда вы удаляете этот объект с карты, восстанавливается "thread-unsafety"?!

2

Предполагая, что вы делаете все это в нескольких потоках, нет, это не потокобезопасно.

Игнорируйте тот факт, что вы получили доступ к TreeMap помощью ConcurrentHashMap - вы получаете ConcurrentHashMap несколько потоков, обращающихся к TreeMap, включая одно или несколько из них, записывающих на карту. Это небезопасно, потому что TreeMap не является потокобезопасным для этой ситуации:

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

  • 0
    Когда я всегда получаю доступ к TreeMap через ConcurrentHashMap, я все равно получаю доступ к нескольким потокам одновременно ...
  • 0
    Потоковая безопасность CHM гарантирует КИСЛОТНОСТЬ ассоциаций ключ-значение, а не самих ключей или значений.
Показать ещё 2 комментария
1

Некоторые из ваших сценариев являются потокобезопасными, некоторые из них не являются:

1. Да, это потокобезопасность, хотя другие потоки не могут видеть вновь созданный TreeMap, пока вы не поместите его в CHM. Но это должно быть тщательно реализовано, чтобы избежать условий гонки - вы должны убедиться, что проверка и вставка выполняются атомарно:

// create an empty treemap somewhere before
TreeMap<Long, String> emptyMap = new TreeMap<>();
...
// On access, use putIfAbsent method to make sure that if 2 threads  
// try to get same key without associated value sumultaneously,
// the same empty map is returned  
if (outerConcurrentMap.putIfAbsent(key, emptyMap) == null) {
    emptyMap = new TreeMap<>();
};
map = outerConcurrentMap.get(key);

2, 3, 4. Нет, вам сначала нужно заблокировать эту TreeMap явной блокировкой или использовать synchronized. TreeMap не синхронизируется сам по себе.

5. Да, это операция выполняется на CHM, поэтому она является потокобезопасной.

Если вам нужна полнопоточная сортированная карта, вместо этого используйте ConcurrentSkipListMap. Он медленнее, чем TreeMap но его внутренняя структура не требует блокировки полной коллекции во время доступа, что делает ее эффективной в параллельной среде.

0

Сам TreeMap не должен быть потокобезопасным. Поскольку выполняются только методы ConcurrentHashMap.

Вы можете сделать следующее:

private final static Map<String, SortedMap <Long,String>> outerConcurrentMap= new ConcurrentHashMap<String, SortedMap <Long,String> >();

static {
    // Just an example
    SortedMap map = Collections.synchronizedSortedMap(new TreeMap(...));
    outerConcurrentMap.put("...",map);
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню