Глубокое понимание ключевого слова volatile в Java

Java задняя часть JVM алгоритм

существуетЕсли кто-то спросит вас, что такое модель памяти Java, отправьте ему эту статью.Мы представили, что для решения проблем атомарности, видимости и упорядочения в параллельном программировании язык Java предоставляет ряд ключевых слов, связанных с параллельной обработкой, таких какsynchronized,volatile,final,concurren包Ждать. существуетПредыдущая статьяВ статье мы также представляемsynchronizedиспользование и принципы. В этой статье разберем еще одно ключевое слово —volatile.

Эта статья вращается вокругvolatileразвернуть, основное введениеvolatileиспользование,volatileпринцип, иvolatileКак обеспечить видимость и гарантии заказа и т. д.

volatileЭто ключевое слово есть не только в языке Java, но и во многих языках, и его использование и семантика также различаются. Особенно в языке C, C++ и Java естьvolatileключевые слова. может использоваться для объявления переменных или объектов. Ниже приведено краткое введение в язык Java.volatileключевые слова.

Использование изменчивого

volatileЧасто называют «легкимsynchronized", также является относительно важным ключевым словом в параллельном программировании на Java. Иsynchronizedразные,volatileэто модификатор переменной, который можно использовать только для изменения переменных. Методы и блоки кода не могут быть изменены.

volatileИспользование относительно простое, просто используйте его при объявлении переменной, к которой могут обращаться несколько потоков одновременно.volatileПросто исправьте это.

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}  

Приведенный выше код является типичной реализацией singleton в виде проверки двойной блокировки, которая используетvolatileКлючевое слово украшает синглтон, к которому могут обращаться несколько потоков одновременно.

Принцип энергозависимости

существуетЕсли кто-то спросит вас, что такое модель памяти Java, отправьте ему эту статью.Мы представили, что для повышения скорости выполнения процессора между процессором и памятью для улучшения добавляется многоуровневый кеш. Однако из-за введения многоуровневого кеша возникает проблема несогласованности кэшированных данных.

Однако дляvolatileпеременная, когдаvolatileКогда переменная записывается, JVM отправляет процессору инструкцию с префиксом блокировки для обратной записи переменной из кэша в основную память системы.

Однако, даже если оно будет записано обратно в память, если значение, кэшированное другими процессорами, все еще старое, возникнут проблемы при выполнении вычислительных операций, поэтому в многопроцессорных системах для обеспечения согласованности кэшей каждого процессора будет осуществляться.缓存一致性协议

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

Итак, если переменнаяvolatileВ случае изменения его значение будет принудительно сбрасываться в основную память после каждого изменения данных. Кэши других процессоров также будут загружать значение этой переменной из основной памяти в свои собственные кеши, поскольку они соответствуют протоколу когерентности кеша. Это гарантируетvolatileВ параллельном программировании его значение отображается в нескольких кешах.

изменчивость и видимость

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

мы вЕсли кто-то спросит вас, что такое модель памяти Java, отправьте ему эту статью.Проанализировано в: Модель памяти Java предусматривает, что все переменные хранятся в основной памяти, каждый поток имеет свою собственную рабочую память, а рабочая память потока сохраняет копию основной памяти, копию переменных, используемых в потоке, Все операции над переменными потоком должны выполняться в рабочей памяти и не могут напрямую читать или записывать в основную память. Разные потоки не могут напрямую обращаться к переменным в рабочей памяти друг друга, а передача переменных между потоками требует синхронизации данных между их собственной рабочей памятью и основной памятью. Поэтому может случиться так, что поток 1 изменяет значение переменной, а поток 2 невидим.

предыдущий оvolatileПринцип был введен в JavavolatileКлючевое слово предоставляет функцию, позволяющую синхронизировать измененную им переменную в основную память сразу после изменения, а изменяемую им переменную обновлять из основной памяти перед каждым использованием. Поэтому вы можете использоватьvolatileДля обеспечения видимости переменных во время многопоточных операций.

изменчивый и упорядоченный

Порядок означает, что порядок выполнения программы соответствует порядку кода.

мы вЕсли кто-то спросит вас, что такое модель памяти Java, отправьте ему эту статью.Проанализировано в: Помимо введения временных интервалов, из-за оптимизации процессора и перестановки инструкций ЦП также может выполнять неупорядоченное выполнение входного кода, напримерload->add->saveможет быть оптимизирован дляload->save->add. Возможны проблемы с заказом.

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

Обычные переменные лишь гарантируют, что правильный результат может быть получен в том месте, где результат присваивания зависит от выполнения метода, но не могут гарантировать, что последовательность операций присваивания переменной согласуется с последовательностью выполнения в программном коде.

Volatile может запрещать перестановку команд, что гарантирует выполнение программы кода в строгом соответствии с порядком кода. Это обеспечивает порядок. одеялоvolatileОперация модифицированной переменной будет выполняться в строгом соответствии с порядком кода,load->add->saveПорядок выполнения такой: загрузить, добавить, сохранить.

изменчивость и атомарность

Атомарность означает, что операция непрерывна и должна выполняться полностью или не выполняться вообще.

мы вВ чем проблема многопоточности в параллельном программировании на Java?Проанализировано в: Поток является базовой единицей планирования ЦП. ЦП имеет концепцию кванта времени и будет планировать потоки в соответствии с различными алгоритмами планирования. Когда поток начинает выполняться после получения кванта времени, после того, как квант времени исчерпан, он теряет право использовать ЦП. Таким образом, в многопоточном сценарии проблемы с атомарностью будут возникать, поскольку временные срезы чередуются между потоками.

В предыдущей статье мы представилиsynchronizedКогда я упомянул, что для обеспечения атомарности необходимо передавать инструкции байт-кодаmonitorenterиmonitorexit,ноvolatileЭто не имеет ничего общего с этими двумя командами.

так,volatileатомарность не гарантируется.

Может использоваться в следующих двух сценарияхvolatileзаменитьsynchronized:

1. Результат операции не зависит от текущего значения переменной или может гарантировать, что только один поток изменит значение переменной.

2. Переменные не должны участвовать в инвариантных ограничениях с другими переменными состояния.

В дополнение к приведенным выше сценариям необходимо использовать другие методы для обеспечения атомарности, такие какsynchronizedилиconcurrent包.

Давайте посмотрим на пример volatile и атомарности:

public class Test {
    public volatile int inc = 0;

    public void increase() {
        inc++;
    }

    public static void main(String[] args) {
        final Test test = new Test();
        for(int i=0;i<10;i++){
            new Thread(){
                public void run() {
                    for(int j=0;j<1000;j++)
                        test.increase();
                };
            }.start();
        }

        while(Thread.activeCount()>1)  //保证前面的线程都执行完
            Thread.yield();
        System.out.println(test.inc);
    }
}

Приведенный выше код относительно прост, то есть нужно создать 10 потоков, а затем выполнить 1000 раз соответственно.i++работать. При нормальных обстоятельствах выходной результат программы должен быть 10000, но все результаты многократного выполнения меньше 10000. Это на самом делеvolatileПричина невозможности удовлетворить атомарность.

Почему это происходит, потому что хотя volatile может гарантироватьincВидимость между несколькими потоками. но не могуinc++атомарность.

Резюме и размышления

мы представилиvolatileключевые слова иsynchronizedключевые слова. Теперь мы знаем,synchronizedАтомарность, упорядоченность и видимость гарантируются. иvolatileНо она может гарантировать только порядок и наглядность.

Затем давайте взглянем на синглтон, реализованный блокировкой с двойной проверкой, которая использоваласьsynchronized, зачем тебе еще нужноvolatile?

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}  

Ответ мы представим в следующей статье: Синхронизировано, он Shengliang изменчив, пожалуйста, обратите внимание на мой блог (www.hollischuang.com) и официальный аккаунт (Холлис).

we