У меня есть пример вложенных карт следующим образом:
private final static Map<String, TreeMap<Long,String>> outerConcurrentMap = new ConcurrentHashMap<>();
Я знаю, что ConcurrentHashMap
является потокобезопасным, но я хочу знать о TreeMap
этой CHM-холдинге, они также потокобезопасны внутри CHM?
Операции, которые я выполняю:
get(K)
.tailMap(K,boolean)
.clear()
CHM.Я хочу создать потокобезопасную структуру в этом сценарии. Является ли вышеуказанная реализация потокобезопасной или нет? Если нет, то предложите решение.
После того, как вы сделали TreeMap<?,?> tm = chm.get(key);
вы больше не находитесь в нитебезопасной территории. В частности, если другой поток обновляет treemap (через CHM или нет), вы можете увидеть или не увидеть изменение. Хуже того, копия карты, которую вы имеете в tm
может быть повреждена...
Один из вариантов - использовать безопасную по потоку карту, такую как ConcurrentSkipListMap.
Простой ответ: нет.
Если ваша карта является ConcurrentHashMap, все операции, влияющие на состояние вашего хэшмапа, являются потокобезопасными. Это вовсе не означает, что объекты, хранящиеся на этой карте, становятся потокобезопасными.
Как это будет работать; вы создаете какой-либо объект и, добавляя его к такой карте, сам объект становится потокобезопасным? И когда вы удаляете этот объект с карты, восстанавливается "thread-unsafety"?!
Предполагая, что вы делаете все это в нескольких потоках, нет, это не потокобезопасно.
Игнорируйте тот факт, что вы получили доступ к TreeMap
помощью ConcurrentHashMap
- вы получаете ConcurrentHashMap
несколько потоков, обращающихся к TreeMap
, включая одно или несколько из них, записывающих на карту. Это небезопасно, потому что TreeMap
не является потокобезопасным для этой ситуации:
Обратите внимание, что эта реализация не синхронизирована. Если несколько потоков обращаются к карте одновременно, и по крайней мере один из потоков изменяет структуру структурно, она должна быть синхронизирована извне.
Некоторые из ваших сценариев являются потокобезопасными, некоторые из них не являются:
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
но его внутренняя структура не требует блокировки полной коллекции во время доступа, что делает ее эффективной в параллельной среде.
Сам 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);
}