Синхронизация через enum-переменную
От: f95.2  
Дата: 25.04.20 22:53
Оценка:
Добрый вечер.
Пусть есть enum:
private enum State {
    STATE1,
    STATE2,
    STATE3;
}


И поле этого типа:
private volatile State state;


Я работаю с ним в нескольких потоках.
Где-то просто читаю:
if (state == State.STATE2) {
   ...
}


Где-то меняю с нотификацией:
synchronized(state) {
    state = State.STATE3;
    state.notifyAll();
}


А где-то жду нотификации:
synchronized(state) {
    while(state != STATE3)
        state.wait();
}


И вопрос: а можно ли так делать?
Насколько я понимаю, в джаве элементы enum'а — это объекты этого самого enum'а.
А переменная типа enum — это просто ссылка на объект.

Соответственно, когда мы делаем state.wait() — мы ждем на мониторе одного объекта,
а когда делаем
state = State.STATE3;
state.notifyAll();

— то это уже нотификация на мониторе другого объекта.

Правильно ли я понимаю ситуацию? И если да, то как правильно синхронизироваться на мониторе enum'а?
Через класс-обертку?
Re: Синхронизация через enum-переменную
От: bzig  
Дата: 26.04.20 02:52
Оценка: 3 (1) +1
F2>И вопрос: а можно ли так делать?

Нельзя

F2>Насколько я понимаю, в джаве элементы enum'а — это объекты этого самого enum'а.

F2>А переменная типа enum — это просто ссылка на объект.
F2>Соответственно, когда мы делаем state.wait() — мы ждем на мониторе одного объекта,

Да

F2>а когда делаем

F2>
F2>state = State.STATE3;
F2>state.notifyAll();
F2>

F2> — то это уже нотификация на мониторе другого объекта.

Только Ява тебе такое в ранйтайме сделать не даст.

    
public static void main(String[] args) {
       Object b1 = new Object();
       Object b2 = new Object();
       Object b = b1;
       synchronized (b) {
           b = b2;
           b.notify(); // IllegalMonitorStateException
       }
}


F2>Правильно ли я понимаю ситуацию? И если да, то как правильно синхронизироваться на мониторе enum'а?

F2>Через класс-обертку?

Простой способ:

synchronized (State.class) {
    ...
}


Правильный способ:

private volatile State state;
private final Object stateLock = new Object(); // синхронизироваться на этом объекте


Простой способ не является рекомендованным, потому что локи предпочтительно делать невидимыми для остальных, тогда как объект класса (даже если сам класс private) может утечь вовне. Предосторожность тут, конечно, на 99.9999% избыточная, но если есть возможность сделать правильно, почему бы и нет.
Отредактировано 26.04.2020 2:53 мамут ушёл, и я пойду . Предыдущая версия .
Re[2]: Синхронизация через enum-переменную
От: f95.2  
Дата: 26.04.20 12:55
Оценка:
Понятно, спасибо.
Re: Синхронизация через enum-переменную
От: Pzz Россия https://github.com/alexpevzner
Дата: 26.04.20 13:01
Оценка:
Здравствуйте, f95.2, Вы писали:

F2>И вопрос: а можно ли так делать?


Кто-то должен атомарность обеспечивать. Причем процессору тоже нужно сказать, что доступ к этой переменной атомарен. А то на многоядерной машинке все будет очень странно работать.

Сомневаюсь, что Ява это делает по умолчанию.
Re[2]: Синхронизация через enum-переменную
От: · Великобритания  
Дата: 26.04.20 15:20
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz> F2>И вопрос: а можно ли так делать?

Pzz> Кто-то должен атомарность обеспечивать.
Спека Java Memory Model обеспечивает. Но это к вопросу не относится, bzig по делу ответил.
avalon/2.0.6
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[3]: Синхронизация через enum-переменную
От: Pzz Россия https://github.com/alexpevzner
Дата: 26.04.20 15:54
Оценка:
Здравствуйте, ·, Вы писали:

Pzz>> F2>И вопрос: а можно ли так делать?

Pzz>> Кто-то должен атомарность обеспечивать.
·>Спека Java Memory Model обеспечивает. Но это к вопросу не относится, bzig по делу ответил.

И что, на каждое обращение к памяти ява вставляет инструкции процессора, обеспечивающие синхронизацию кешей? Что-то слабо верится...
Re[4]: Синхронизация через enum-переменную
От: · Великобритания  
Дата: 26.04.20 17:29
Оценка: +1
Здравствуйте, Pzz, Вы писали:

Pzz> ·>Спека Java Memory Model обеспечивает. Но это к вопросу не относится, bzig по делу ответил.

Pzz> И что, на каждое обращение к памяти ява вставляет инструкции процессора, обеспечивающие синхронизацию кешей? Что-то слабо верится...
Я не совсем понимаю про что ты. Атомарность это либо всё, либо ничего. Т.е. когда пишется значение, то читается либо старое целиком, либо новое целиком. А не так, чтобы первые 32 бита ещё старые, а вторые 32 бита уже новые.
Кеши и гарантия видимости значений между потоками это про другое, ты наверное happens-before имел в виду. У него в коде synchronized для этого.
avalon/2.0.6
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re: Синхронизация через enum-переменную
От: StanislavK Великобритания  
Дата: 28.04.20 06:40
Оценка: +2
Здравствуйте, f95.2, Вы писали:

F2>И поле этого типа:

F2>
F2>private volatile State state;
F2>


F2>Я работаю с ним в нескольких потоках.

F2>Где-то просто читаю:
F2>
F2>if (state == State.STATE2) {
F2>   ...
F2>}
F2>


К тому, что уже было сказано я бы только добавил, что раз уж synchronized все равно используется, что я бы убрал volatile и читал бы тоже в synchronized. Если конечно нет каких-то причин использовать именно volatile.
Re[4]: Синхронизация через enum-переменную
От: vsb Казахстан  
Дата: 02.05.20 22:00
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>И что, на каждое обращение к памяти ява вставляет инструкции процессора, обеспечивающие синхронизацию кешей? Что-то слабо верится...


Не на каждое, а там, где synchronized заканчивается.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.