Не паникуйте при встрече | Здравствуйте, можете рассказать о ключевом слове volatile? (пять)

Java опрос
Не паникуйте при встрече | Здравствуйте, можете рассказать о ключевом слове volatile? (пять)

Это 29-й день моего участия в Gengwen Challenge.Подробности о мероприятии:Обновить вызов.
Сразу после предыдущегоПривет, можешь рассказать о ключевом слове volatile? (Четыре)

4.6 happens-before

В принципе должно бытьJMMглава говорит,happens-beforeПринципJMMосновные понятия. Но поскольку все дело в наглядности и порядке, давайте сначала кратко упомянем об этом.

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

4.6.1 happens-before && as-if-serial

happens-beforeвзаимоотношения в природе иas-if-serialСемантика — это одно и то же.

  • happens-beforeа такжеas-if-serialУбедитесь, что результаты многопоточного и однопоточного выполнения не изменились соответственно.
  • as-if-serialВидимость, которую семантика создает для пользователя, состоит в том, что в последовательности программы выполняется один поток;happens-beforeВнешний вид, вызванный семантикой, положительный Правильно синхронизированная многопоточная программаhappens-beforeвыполняются в указанном порядке.

Цель этих двух правил — максимально улучшить параллелизм выполнения программы без изменения результата выполнения программы.

4.6.2 happeds-beforeправило

**"JSR-133: Модель памяти Java и спецификация потоков"** определяет следующие правила "происходит до".

Правила порядка выполнения программы: каждая операция в потоке выполняется до любых последующих операций в этом потоке.

правила порядка программыПроще говоря, чтобы обеспечить параллелизм, вы можете оптимизировать и настроить порядок выполнения так, как вам хочется, но результат всегда один и тот же. Это общая программа.

Следите за правилами блокировки: отпирание замка происходит до последующего запирания замка.

Правила блокировки монитора

    static int y = 1;

     static void testMonitorRule(){
         synchronized(Object.class){
             if(y==1){
                 y=2;
             }
         }
    }

Поток 1 получает блокировку первым и изменяет значение y на 2. После того, как поток 2 получает блокировку, он может непосредственно видеть, что y==2.

Правила для изменчивых переменных: запись в изменчивое поле происходит до любой последующей записи в изменчивое поле. читать.

правила изменяемой переменной

    static int i = 1;
    static volatile boolean flag = false;
    static void testVolatileRuleReader(){
       i=2;//1
       flag=true;//2
    }
    static void testVolatileRuleWriter(){
        if(flag){//3
            assert i == 2;//4
        }
    }

Итак, шаг 3 — это чтение, и вы можете увидеть запись шага 2.

Переходный: если А происходит раньше В, а В происходит раньше С, то А происходит раньше С.

транзитивное правило, чуть вышеvolatileВ примере правила говорится, что шаг 1 должен произойти до шага 4.

правило start(): если поток A выполняет операцию ThreadB.start() (запускает поток B), то Операция ThreadB.start() происходит перед любой операцией в потоке B.

правила запуска()

    static void testStartRule(){
        AtomicInteger x = new AtomicInteger(1);
        final Thread t = new Thread(() -> {
            assert x.get() == 2;
        });
        x.set(2);
        t.start();
    }

Основной поток вызывает дочерний потокt.start()Все предыдущие операции с общими переменными видны дочерним потокам.

Правило join(): если поток A выполняет операцию ThreadB.join() и успешно возвращается, то любая операция в потоке B происходит до того, как поток A успешно вернется из операции ThreadB.join().

правила присоединения()

static void testJoinRule() throws InterruptedException {
        AtomicInteger x = new AtomicInteger(1);
        final Thread t = new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            x.set(2);
        });
        t.start();
        t.join();
        assert  x.get() == 2;
    }

вызвать дочерний поток в основном потокеt.join(), все изменения общих переменных дочерними потоками видны основному потоку.

5 Резюме

5.1 volatileсценарии использования

volatileсуществуетJavaОн часто используется в параллелизме, напримерAtomicв упаковкеvalue,так же какAbstractQueuedLongSynchronizerсерединаstateпеременныеvolatileУкрашено, чтобы гарантировать видимость памяти.

В нашем процессе разработки также есть некоторые приложения, такие как.

Используйте один поток, чтобы остановить другой поток, изменив бит флага

public static volatile   boolean run = true;

    public static void main(String[] args) throws InterruptedException {
        final Thread t = new Thread(() -> {
            int i = 0;
            while (!run) {
                i++;
                Thread.yield();
            }
        });
        t.start();
        TimeUnit.SECONDS.sleep(10);
        run= true;
    }

Блокировки с двойной проверкой реализуют шаблон singleton.

public class DoubleCheckingLock {
    private static volatile Instance instance;
    public static Instance getInstance(){
        if(instance == null){
            synchronized (DoubleCheckingLock.class){
                if(instance == null){
                    instance = new Instance();
                }
            }
        }
        return instance;
    };
    static class  Instance { }
}

В частности, как этого добиться, см. ** "Искусство параллельного программирования на Java"** в этой хорошей книге.

5.2 Закрытие

Эта статья начинается с примера и приводит к проблемам видимости и порядка работы с общими переменными в многопоточной среде. В сочетании с аппаратной средой анализируется, что для эффективного использования ресурсов компьютера и улучшения параллелизмаCPUКэширование было введено, чтобы вызвать проблемы. Чтобы решить проблему согласованности, вызванную кешем, была проанализирована еще одна волна.MESIСоглашение было окончательно проанализировано.volatileОсновной принцип内存屏障.

На вопросы, упомянутые в начале статьи, можно будет ответить уже после прочтения этой статьи. оsynchronizedВопрос в этой частиsynchronizedАнализ воссоединения глав.


Брат, не паникуй! Не стесняйтесь оставлять лайки, обсуждать и комментировать. Добро пожаловать в колонку интервьюНе паникуйте, когда сталкиваетесь | Параллельное программирование на Java, Не беспокойтесь о повышении зарплаты во время собеседования. Также добро пожаловать, чтобы следовать за мной, я должен быть лучшим человеком.