2011-01-26 3 views
1

Если у меня есть следующее заявление:Являются ли цепные поточные безопасные коллекции потоками безопасными?

Map<String, Map<String, Person>> families = 
    Collections.synchronizedMap(new HashMap<String, Map<String, Person>>()); 

Если я тогда цепь вызова следующим образом:

families.get(lastName).put(firstName, new Person()); 

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

EDIT Отличные баллы, сделанные в обоих ответах до сих пор благодаря куча! Но теперь я думаю, что если бы я сделал это:

families.put(lastName, Collections.synchronizedMap(new HashMap<String, Person>()); 

затем сделал мой прикован вызов, является то, что вся цепочка поточно? Возможно ли, что между get(lastName) и put(firstName, new Person()) другой поток может получить внутреннюю карту? Я думаю, что если я хочу, чтобы целая цепочка была безопасной, мне нужно поместить ее внутри синхронизированного блока, но мне также интересно, будет ли это также работать ...

ответ

1

Возможно, что между вызовами внешнего get() и внутреннего put() другой поток вызывает внешний get() и получает ту же внутреннюю карту. Но поскольку он синхронизирован, он все равно должен быть безопасным.

Проблема заключается в том, что вы помещаете что-то во внешнюю карту. Как поток определяет, нужно ли создавать новую внутреннюю карту? Предположим, что у вас есть такой код:

if (!families.containsKey(lastName)) { 
    families.put(lastName, Collections.synchronizedMap(new HashMap<String, Person>()); 
} 

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

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

4

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

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

4

Внутренняя карта не нить-сейф.

Если другой поток делает

families.get(lastName).put(firstName, new Person()); 

с жеlastName, то это возможно одна нить, чтобы получить внутреннюю карту, то другой поток получает внутреннюю карту, то оба вызова put на в то же время и сломать все.

Использование synchronizedMap часто не достаточно для правильного параллелизма - обычно вы хотите явно заблокировать вокруг каждой сделки, а не вокруг каждого вызова метода.

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