Мне нужно знать, когда я должен добавить блок синхронизации в свой код при использовании ConcurrentHashMap. Предположим, у меня есть метод, например:Когда и как следует использовать дополнительную синхронизацию ConcurrentHashMap?
private static final ConcurrentMap<String, MyObjectWrapper> myObjectsCache = new ConcurrentHashMap<>(CACHE_INITIAL_CAPACITY);
public List<MyObject> aMethod(List<String> ids, boolean b) {
List<MyObject> result = new ArrayList<>(ids.size());
for (String id : ids) {
if (id == null) {
continue;
}
MyObjectWrapper myObjectWrapper = myObjectsCache.get(id);
if (myObjectWrapper == null) {
continue;
}
if (myObjectWrapper.getObject() instanceof MyObjectSub) {
((MyObjectSub) myObjectWrapper.getObject()).clearAField();
myObjectWrapper.getObject().setTime(System.currentTimeMillis());
}
result.add(myObjectWrapper.getObject());
if (b) {
final MyObject obj = new MyObject(myObjectWrapper.getObject());
addObjectToDb(obj);
}
}
return result;
}
Как я могу эффективно сделать этот метод одновременно? Я думаю, что «get» безопасен, но как только я получу значение из кеша и обновляю поля кэшированного объекта, могут возникнуть проблемы, связанные с тем, что другой поток может получить одну и ту же оболочку и попытаться обновить один и тот же базовый объект ... Должен ли я добавить синхронизацию? И если да, то следует ли мне синхронизировать с «get» до конца цикла или всего цикла?
Может быть кто-то может поделиться некоторыми более конкретные руководящие принципы надлежащего и эффективного использования ConcurrentHashMap, когда еще некоторые операции должны быть сделаны на карте ключей/значений внутри петель и т.д. ...
я был бы очень благодарен.
EDIT: Некоторого контекст вопрос: я в настоящее время работаю над рефакторингом некоторых классов дао в производстве кода и несколько классов, используемых HashMaps для кэширования данных, извлекаемых из базы данных. Все методы, использующие кеш (для записи или чтения), содержали весь контент в блоке синхронизации (кеш) (играя безопасно?). У меня нет большого опыта параллелизма, и я действительно хочу использовать эту возможность для изучения. Я наивно изменил HashMaps на ConcurrentHashMaps и теперь хочу удалить синхронизированные блоки, где они необходимы. Все кеши используются для записи и чтения. Представленный метод основан на одном из методов, которые я изменил, и теперь я пытаюсь узнать, когда и в какой степени синхронизироваться. Методы clearAField просто изменяет значение одного из полей обернутого объекта POJO, а addObjectToDb пытается добавить объект в базу данных.
Другого примера будет заправка кэша:
public void findAll() throws SQLException{
// get data from database into a list
List<Data> data=getAllDataFromDatabase();
cacheCHM.clear();
cacheCHM.putAll(data);
}
В этом случае я должен поставить ясный и putAll внутри синхронизации (cacheCHM) блок, не так ли?
Я пытался найти и прочитать некоторые сообщения/статьи о правильном и эффективном использовании CHM, но большинство имеют дело с одиночными операциями, без петель и т.д .... Лучшее, что я нашел бы: http://www.javamadesoeasy.com/2015/04/concurrenthashmap-in-java.html
Это в значительной степени зависит от вашей логики приложения. – pintxo
Если вам нужно обновить полученное значение для обеспечения потокобезопасности, вы должны синхронизировать его с самим объектом. «ConcurrentHashMap» защищает только структуру самой карты (т. Е. Отношение ключей к значениям), а не содержащиеся значения. –
Я согласен с @Jim, параллельная карта будет защищать только структуру (т. Е. Отношение ключей к значениям). Я хочу добавить к нему еще одну вещь. В соответствии с приведенным выше контекстом кода вы читаете только значение ie.e myObjectsCache.get (id), поэтому для этой цели вам может даже не понадобиться параллельная карта, пока вы не вызовете map.put(). – pbajpai21