Java - volatile ключевое слово также для не примитивов
Я не уверен, что ключевое слово volatile также должно использоваться для не-примитивов. У меня есть член класса, который задан/назначен одним потоком и доступен другим потоком. Должен ли я объявлять этот элемент изменчивым?
private /* volatile */ Object o;
public void setMember(Object o) {
this.o = o;
}
public Object getMember() {
return o;
}
Здесь setMember (...) вызывается одним потоком, а getMember() вызывается другим.
Если бы это было логическое, например, ответ был бы да.
Я использую Java 1.4, и член в этом случае доступен только для чтения. Поэтому я только забочусь о видимости в этом случае, поэтому мой вопрос о ключевом слове volatile.
Ответы
Ответ 1
Да - volatile
имеет то же значение для полей ссылочного типа, что и для полей примитивного типа. За исключением того, что в случае ссылочных типов члены объекта, к которому относится поле, также должны быть предназначены для многопоточного доступа.
Ответ 2
Вы можете, и это может быть полезно, но помните, что ключевое слово применяется только к настройке ссылки. Это не влияет на многопоточность видимости свойств внутри этого объекта. Если это состояние, вы, вероятно, захотите синхронизировать каждый доступ к нему в любом случае, чтобы обеспечить необходимые действия перед отношениями.
Ответ 3
Да, ваш код верен. В этом случае сама эта ссылка является изменчивой, поэтому шансы на ссылку автоматически отображаются во всех других потоках, но не на изменения ссылки на объект.
Ответ 4
Если мы посмотрим на класс AtomicInteger
, он объявил value
как volatile
, поэтому его можно использовать в многопоточной среде без какой-либо проблемы с кешем потока.
public class AtomicInteger {
private volatile int value;
/**
* Gets the current value.
*
* @return the current value
*/
public final int get() {
return value;
}
/**
* Sets to the given value.
*
* @param newValue the new value
*/
public final void set(int newValue) {
value = newValue;
}
}
Но если вы считаете ссылкой на AtomicInteger, то полка будет изменена различными объектами AtomicInteger многими потоками; то вам также нужна летучесть для этой справки.
private volatile AtomicInteger reference = new AtomicInteger(0);
В основном это не так; изменится только значение объекта; поэтому объявите его окончательным.
private final AtomicInteger reference = new AtomicInteger(0);