Как я могу использовать энергозависимое ключевое слово в Java правильно?

Скажите, что у меня есть два потока и объект. Один поток присваивает объект:

public void assign(MyObject o) {
    myObject = o;
}

Другой поток использует объект:

public void use() {
    myObject.use();
}

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

Большое спасибо.

14
задан Bert 18 November 2011 в 14:41
поделиться

4 ответа

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

2
ответ дан 1 December 2019 в 12:12
поделиться

Я пытаюсь понять, когда использовать volatile, а когда нет

Вам следует избегать его использования. Вместо этого используйте AtomicReference (или другой атомарный класс, если необходимо). Эффекты памяти такие же, и цель намного яснее.

Я настоятельно рекомендую прочитать превосходный Java Concurrency in Practice для лучшего понимания.

11
ответ дан 1 December 2019 в 12:12
поделиться

Здесь есть несколько сбивающих с толку комментариев: чтобы уточнить, ваш код неверен в его нынешнем виде, предполагая, что два разных потока вызывают assign () и используйте () .

При отсутствии volatile или другой связи «происходит раньше» (например, синхронизация по общей блокировке) любая запись в myObject в assign () не гарантируется, что его увидит поток, вызывающий use () - ни сразу, ни вовремя, ни когда-либо.

Да, volatile - это один из способов исправить это (при условии, что это некорректное поведение - есть вероятные ситуации, когда вас это не волнует!).

Вы совершенно правы в том, что поток 'use' может видеть любое 'закешированное' значение myObject , включая то, которое ему было присвоено во время построения, и любое промежуточное значение (опять же, при отсутствии другого -перед точками).

0
ответ дан 1 December 2019 в 12:12
поделиться

Оставив позади сложные технические детали, вы можете увидеть volatile меньше или больше как синхронизированный модификатор для переменных . Если вы хотите синхронизировать доступ к методам или блокам, вы обычно хотите использовать модификатор synchronized следующим образом:

public synchronized void doSomething() {}

Если вы хотите «синхронизировать» доступ к переменным, тогда вы хотели бы использовать модификатор volatile :

private volatile SomeObject variable;

За кулисами они делают разные вещи, но эффект тот же: изменения сразу видны для следующего потока доступа .

В вашем конкретном случае я не думаю, что модификатор volatile имеет какое-либо значение. volatile никоим образом не гарантирует, что поток, назначающий объект, будет запускаться перед потоком, использующим объект.Может быть и наоборот. Вероятно, вы просто хотите сначала выполнить нулевую проверку в методе use () .

Обновление : также см. эту статью :

Доступ к переменной действует так, как если бы заключен в синхронизированный блок, синхронизированный сам с собой. Мы говорим «действует так, как если бы» во втором пункте, потому что для программиста по крайней мере (и, вероятно, в большинстве реализаций JVM) нет фактического объекта блокировки .

6
ответ дан 1 December 2019 в 12:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: