Достаточно ли безопасен поток в точке входа синхронизированного метода Java?
У меня есть класс Singleton, обрабатывающий вид кэша с различными объектами в Hashmap. (Формат ключа напрямую связан с типом объекта, хранящегося на карте - следовательно, карта имеет)
На карте возможны три различных действия: добавить, получить, удалить.
Я обеспечил доступ к карте с помощью метода публичной точки входа (без интенсивного доступа):
public synchronized Object doAction(String actionType, String key, Object data){
Object myObj = null;
if (actionType.equalsIgnorecase("ADD"){
addDataToMyMap(key,data);
} else if (actionType.equalsIgnorecase("GET"){
myObj = getDataFromMyMap(key);
} else if (actionType.equalsIgnorecase("REM"){
removeDataFromMyMap(key);
}
return myObj;
}
Заметки:
Карта является частной. Методы addDataToMyMap(), getDataFromMyMap() и removeDataFromMyMap() являются закрытыми. Только метод точки входа является общедоступным, и ничего кроме статического getInstance() самого класса.
Вы подтверждаете, что это потокобезопасный для одновременного доступа к карте, поскольку нет другого способа использовать карту, кроме как с помощью этого метода?
Если это безопасная карта, я думаю, этот принцип может быть применен к любому другому виду общего ресурса.
Заранее большое спасибо за ваши ответы.
Дэвид
8 ответов
Мне нужно будет увидеть вашу реализацию ваших методов, но этого может быть достаточно. НО я бы порекомендовал вам использовать Map из API Collection из java, тогда вам не нужно будет синхронизировать ваш метод, если вы не поделились каким-либо другим экземпляром.
Прочитайте это: http://www.java-examples.com/get-synchronized-map-java-hashmap-example
Да, ваш класс будет потокобезопасным, если единственной точкой входа является doAction.
Это совершенно безопасно. До тех пор, пока все потоки обращаются к нему с помощью общей блокировки, которая в данном случае является объектом, она является поточно-ориентированной. (Другие ответы могут быть более производительными, но ваша реализация безопасна.)
Если твой cache
класс имеет личное HashMap
и у вас есть три метода, и все public synchronized
и не static
и если у вас нет другого public
переменная экземпляра, то я думаю, что ваш кэш thread-safe
,
Лучше разместить свой код.
Как это трудно определить, является ли код потокобезопасным. Важная информация, отсутствующая в вашем примере:
- Являются ли методы публичными
- Синхронизированы ли методы
- Это карта доступна только через методы
Я бы посоветовал вам изучить синхронизацию, чтобы понять проблемы и решить их. Изучение класса ConcurrentHashMap даст дополнительную информацию о вашей проблеме.
Вы должны использовать ConcurrentHashMap. Он предлагает лучшую пропускную способность, чем синхронизированный doAction, и лучшую безопасность потоков, чем Collections.synchronizedMap().
Это зависит от вашего кода. Как кто-то еще сказал, вы можете использовать Collections.synchronizedMap. Однако это синхронизирует только отдельные вызовы методов на карте. Так что если:
map.get(key);
map.put(key,value);
Выполняются одновременно в двух разных потоках, один будет блокироваться, пока другой не выйдет. Однако, если ваш критический раздел больше, чем один вызов на карту:
SomeExpensiveObject value = map.get(key);
if (value == null) {
value = new SomeExpensiveObject();
map.put(key,value);
}
Теперь давайте предположим, что ключа нет. Первый поток выполняется и возвращает нулевое значение. Планировщик возвращает этот поток и запускает поток 2, который также возвращает нулевое значение. Он создает новый объект и помещает его в карту. Затем поток 1 возобновляет работу и делает то же самое, поскольку он все еще имеет нулевое значение.
Это где вы хотите больший блок синхронизации вокруг вашего критического раздела
SomeExpensiveObject value = null;
synchronized (map) {
value = map.get(key);
if (value == null) {
value = new SomeExpensiveObject();
map.put(key,value);
}
}
Вы можете использовать Collections.synchronizedMap для синхронизации доступа к Map
,