1) Если два потока одновременно читают и записывают в общую переменную, то для этого недостаточно использовать ключевое слово volatile. В этом случае необходимо использовать синхронизированный, чтобы гарантировать, что чтение и запись переменной являются атомарными. Чтение или запись изменчивой переменной не блокирует чтение или запись потоков. Чтобы это произошло, вы должны использовать ключевое слово synchronized вокруг критических секций.
2) В качестве альтернативы синхронизированному блоку вы также можете использовать один из множества атомарных типов данных, найденных в пакете java.util.concurrent. Например, AtomicLong или AtomicReference или один из других.
Это потокобезопасно, если у вас есть один поток записи и несколько потоков чтения.
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
Примечание: если помощник является неизменяемым, тогда нет необходимости использовать ключевое слово volatile. Здесь синглтон будет работать правильно.
В случае счетчика, который увеличивается на несколько потоков (операция чтения чтения), не даст правильного ответа. Это условие также проиллюстрировано расой.
public class Counter{
private volatile int i;
public int increment(){
i++;
}
}
ПРИМЕЧАНИЕ: изменчивость здесь не поможет.