Я пытаюсь разобраться с логикой лок-объектов на нескольких примерах,
речь всегда пойдет об одном экземпляре MyClass
:
Пример 1:
Если поток один зайдет в метод a()
, то поток два в метод b()
, уже войти не сможет, пока первый поток из метода a()
, не выйдет? Потому что объект монитор у нас один и тот-же? Или не правильно?
MyClass {
final Object obj = new Object();
void a() {
synchronized(obj) {
// do something...
}
}
void b() {
synchronized(obj) {
// do something...
}
}
}
Пример 2:
Если поток один зайдет в метод a()
, то поток два в метод b()
, войти сможет. Потому что объекты мониторов у нас разные. Или не правильно?
MyClass {
final Object obj1 = new Object();
final Object obj2 = new Object();
void a() {
synchronized(obj1) {
// do something...
}
}
void b() {
synchronized(obj2) {
// do something...
}
}
}
Пример 3:
Если поток один зайдет в метод a()
, то поток два в метод b()
, уже войти не сможет, пока первый поток из метода a()
, не выйдет? Потому что объект монитор у нас один и тот-же? Как в примере один.
Значит ли это, что я могу спокойно обращаться к методам read
и write
, и быть уверенным что потери данных, из-за гонки, или кэширования не произойдет?
MyClass {
final Map<String, String> map = new HashMap<>();
void a() {
String read(final String key, final String value) {
synchronized(map) {
this.map.put(key, value);
}
}
String write(final String key) {
synchronized(map) {
return this.map.get(key);
}
}
}
Пример 4:
Будет ли являться такой код потокобезопасным в ситуации, если обращаться к методам read
и write
, из разных потоков? Почему? Что может произойти?
MyClass {
volatile Map<String, String> map = new HashMap<>();
final Object readLock = new Object();
final Object writeLock = new Object();
String read(final String key, final String value) {
synchronized(readLock) {
this.map.put(key, value);
}
}
String write(final String key) {
synchronized(writeLock) {
return this.map.get(key);
}
}
}
Спасибо.
Disclaimer: формально оба потока смогут зайти в любые методы во всех примерах - они могут остановиться на synchronized-блоке, который расположен внутри метода. Понятно, что интересовала именно синхронизация, поэтому дальше идет речь исключительно про блокировку одного потока другим в критической секции.
Да, все верно.
Тоже все верно.
Да, но здесь нужно быть очень аккуратным (и, возможно, я даже ошибусь с написанием этого ответа). Порядок операций в Java определяет Java Memory Model, из которой проистекает отношение happens-before, которым и нужно оперировать для определения порядка видимости изменений: happens-before между операциями X и Y гарантирует, что результат операции Х будет виден последующей операции Y (X happens before Y -> "X происходит до Y"). Сам по себе Map/HashMap не определяет отношение hb, но у Java есть следующие обязательные отношения hb:
Насколько понимаю, данный подход безопасен, но лучше сразу завернуть целиком метод в synchronized и/или взять ConcurrentHashMap - если интересно, почему я ттак беспокоюсь, можно почитать легко находимые статьи про double checked locking, в которых описывается похожий случай, который не работает. К сожалению, у меня сейчас нет времени, чтобы ответить на этот вопрос твердо и точно, общим подходом в таких случаях является better safe than sorry и жертва теоретической производительности в пользу гарантий.
Нет, потому что он определяет отдельно порядок чтений и отдельно порядок записи. Здесь нет отношений hb от записи к чтению, поэтому поток совершенно точно вправе увидеть любой мусор.
Позволю себе минуту брюзжания:
тот-же
Тот же
Или не правильно
неправильно
поток два в метод b(), уже войти не сможет
первый поток из метода a(), не выйдет
поток два в метод b(), войти сможет
поток два в метод b(), уже войти не сможет
поток из метода a(), не выйдет
обращаться к методам read и write, из разных потоков
Ни одна из этих запятых не нужна, здесь практически везде подлежащее-сказуемое, и между ними запятые (без дополнительных оборотов и прочих усложнений) не ставятся
потери данных, из-за гонки, или кэширования
здесь другой случай, но тоже не нужны
Если хотите, быстрые read/write блокировки, то можно использовать ReentrantReadWriteLock.
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
Необходимо реализовать CRUD операции с БД MySQLИспользую Repository для доступа у данным
Здравствуйте! Мне нобходимо найти способ хранить тайлы, с размерами больше 1x1 в стандартной тайл-карте (tilemap, как по русски то?)
Подскажите пожалуйста, как "утолстить" шрифт в IntelliJ IDEА? Просто в Windows он настолько тонок, что смотреть неприятно