Когда именно вы используете ключевое слово volatile в Java? [duplicate]

85
задан Ravindra babu 17 September 2016 в 17:57
поделиться

4 ответа

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

class BadExample {
    private volatile int counter;

    public void hit(){
        /* This operation is in fact two operations:
         * 1) int tmp = this.counter;
         * 2) this.counter = tmp + 1;
         * and is thus broken (counter becomes fewer
         * than the accurate amount).
         */
        counter++;
    }
}

приведенный выше пример плохой, потому что вам нужна составная атомарность.

 class BadExampleFixed {
    private int counter;

    public synchronized void hit(){
        /*
         * Only one thread performs action (1), (2) at a time
         * "atomically", in the sense that other threads can not 
         * observe the intermediate state between (1) and (2).
         * Therefore, the counter will be accurate.
         */
        counter++;
    }
}

Теперь вернемся к действительному примеру:

 class GoodExample {
    private static volatile int temperature;

    //Called by some other thread than main
    public static void todaysTemperature(int temp){
        // This operation is a single operation, so you 
        // do not need compound atomicity
        temperature = temp;
    }

    public static void main(String[] args) throws Exception{
        while(true){
           Thread.sleep(2000);
           System.out.println("Today's temperature is "+temperature);
        }
    }
}

А почему нельзя просто использовать private static int temperature ? Фактически, вы можете (в том смысле, что ваша программа не взорвется или что-то в этом роде), но изменение температуры другим потоком может быть или не быть «видимым» для основного потока.

В основном это означает, что возможно, что ваш app. продолжает писать Текущая температура равна 0 навсегда, если вы не используете volatile (на практике значение имеет тенденцию становиться видимым со временем. Однако вы не должны рисковать не использовать volatile при необходимости, так как это может привести к неприятным ошибкам (вызванным полностью построенными объектами и т. д.).

Если вы поместите ключевое слово volatile на то, что не требует volatile , это не повлияет на правильность вашего кода (т.е. поведение не изменится). С точки зрения производительности, это будет зависеть от реализации JVM. Теоретически вы можете получить небольшое снижение производительности, потому что компилятор не может этого сделать. переупорядочивание оптимизаций, необходимо сделать недействительным кэш ЦП и т. д., но опять же компилятор может доказать, что к вашему полю никогда нельзя получить доступ для нескольких потоков, и полностью удалить эффект ключевого слова volatile и скомпилировать его в идентичные инструкции.

РЕДАКТИРОВАТЬ:
Ответ на этот комментарий:

Хорошо, но почему мы не можем синхронизировать сегодняшнюю температуру и создать синхронизированный получатель температуры?

Можно, и он будет вести себя правильно. Все, что можно сделать с помощью volatile , можно сделать с помощью synchronized , но не наоборот. Есть две причины, по которым вы можете предпочесть volatile , если можете:

  1. Менее подвержены ошибкам: это зависит от контекста, но во многих случаях использование volatile менее подвержено ошибкам параллелизма, например, блокировка при удержании блокировки, взаимоблокировки и т. д.
  2. Более высокая производительность: в большинстве реализаций JVM volatile может иметь значительно более высокую пропускную способность и большую задержку. Однако в большинстве приложений разница слишком мала, чтобы иметь значение.
107
ответ дан 24 November 2019 в 08:20
поделиться

http://mindprod.com/jgloss/volatile.html

«Ключевое слово volatile используется для переменных, которые могут быть изменены одновременно другими потоками»

«Так как other потоки не могут видеть локальные переменные, нет необходимости помечать локальные переменные как изменчивые. Вам нужно синхронизировать изменения для координации изменений переменных из разных потоков, но часто volatile достаточно просто посмотреть на них »

2
ответ дан 24 November 2019 в 08:20
поделиться

Volatile наиболее полезен в алгоритмах без блокировки. Вы помечаете переменную, содержащую общие данные, как изменчивую, когда вы не используете блокировку для доступа к этой переменной и хотите, чтобы изменения, сделанные одним потоком, были видны в другом, или вы хотите создать отношение «происходит после», чтобы гарантировать, что вычисления не переупорядочивать, опять же, чтобы изменения стали заметны в нужное время.

Поваренная книга JMM описывает, какие операции можно переупорядочить, а какие нет.

14
ответ дан 24 November 2019 в 08:20
поделиться

volatile также можно использовать для безопасной публикации неизменяемых объектов в многопоточной среде.

Объявление поля типа public volatile ImmutableObject foo гарантирует, что все потоки всегда видят доступную в данный момент ссылку на экземпляр.

См. Параллелизм Java на практике для получения дополнительной информации по этой теме.

5
ответ дан 24 November 2019 в 08:20
поделиться
Другие вопросы по тегам:

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