Какое ключевое слово volatile полезно для

На работе сегодня я наткнулся наvolatile Ключевое слово в Java. Не очень знакомый с этим, я нашел это объяснение:

Java theory and practice: Managing volatility

Учитывая детали, в которых эта статья объясняет данное ключевое слово, вы когда-нибудь использовали его или могли когда-нибудь увидеть случай, когда вы могли бы использовать это ключевое слово правильным образом?

Ответы на вопрос(22)

Important point about volatile:

Synchronization in Java is possible by using Java keywords synchronized and volatile and locks. In Java, we can not have synchronized variable. Using synchronized keyword with a variable is illegal and will result in compilation error. Instead of using the synchronized variable in Java, you can use the java volatile variable, which will instruct JVM threads to read the value of volatile variable from main memory and don’t cache it locally. If a variable is not shared between multiple threads then there is no need to use the volatile keyword.

источник

Example usage of volatile:

public class Singleton {
    private static volatile Singleton _instance; // volatile variable
    public static Singleton getInstance() {
        if (_instance == null) {
            synchronized (Singleton.class) {
                if (_instance == null)
                    _instance = new Singleton();
            }
        }
        return _instance;
    }
}

Мы создаем экземпляр лениво во время первого запроса.

Если мы не сделаем_instance переменнаяvolatile затем поток, который создает экземплярSingleton не может общаться с другим потоком. Таким образом, если поток A создает экземпляр Singleton и сразу после создания процессор испортит и т. Д., Все остальные потоки не смогут увидеть значение_instance как не нуль, и они будут верить, что это все еще назначено нуль.

Почему это происходит? Поскольку потоки считывателя не блокируются, и пока поток записывающего устройства не выйдет из синхронизированного блока, память не будет синхронизирована, и значение_instance не будет обновляться в основной памяти. С ключевым словом Volatile в Java это обрабатывается самой Java, и такие обновления будут видны всем потокам читателей.

Conclusion: volatile keyword is also used to communicate the content of memory between threads.

Example usage of without volatile:

public class Singleton{    
    private static Singleton _instance;   //without volatile variable
    public static Singleton getInstance(){   
          if(_instance == null){  
              synchronized(Singleton.class){  
               if(_instance == null) _instance = new Singleton(); 
      } 
     }   
    return _instance;  
    }

Код выше не является потокобезопасным. Хотя он проверяет значение экземпляра еще раз в синхронизированном блоке (по соображениям производительности), JIT-компилятор может переставить байт-код таким образом, чтобы ссылка на экземпляр была установлена до того, как конструктор завершит свое выполнение. Это означает, что метод getInstance () возвращает объект, который, возможно, не был полностью инициализирован. Чтобы сделать код потокобезопасным, ключевое слово volatile может использоваться начиная с Java 5 для переменной экземпляра. Переменные, помеченные как volatile, становятся видимыми для других потоков только после того, как конструктор объекта полностью завершит свое выполнение.
Источник

enter image description here

volatile usage in Java:

Отказоустойчивые итераторыtypically реализовано с использованиемvolatile счетчик в списке объектов.

When the list is updated, the counter is incremented. When an Iterator is created, the current value of the counter is embedded in the Iterator object. When an Iterator operation is performed, the method compares the two counter values and throws a ConcurrentModificationException if they are different.

Реализация отказоустойчивых итераторов обычно легковесна. Они обычно полагаются на свойства структур данных конкретной реализации списка. Там нет общей картины.

 20 дек. 2017 г., 03:30
& Quot; который будет инструктировать потокам JVM считывать значение энергозависимой переменной из основной памяти и не кэшировать его локально. & quot; хорошая точка зрения
 26 февр. 2018 г., 10:23
Для безопасности потока можно пойти сprivate static final Singleton _instance; также.
 24 мая 2017 г., 19:15
«Отказоустойчивые итераторы обычно реализуются с использованием энергозависимого счетчика». - больше не бывает, слишком дорогоbugs.java.com/bugdatabase/view_bug.do?bug_id=6625725
 25 нояб. 2017 г., 22:18
безопасны ли двойные проверки для _instance? я думал, что они не безопасны даже с летучими

volatile это использоватьvolatile boolean переменная как флаг для завершения потока. Если вы запустили поток и хотите иметь возможность безопасно прервать его из другого потока, он может периодически проверять флаг. Чтобы остановить это, установите флаг в true. Делая флагvolatile, вы можете убедиться, что поток, который его проверяет, увидит, что он был установлен в следующий раз, когда он проверяет его, даже не используяsynchronized блок.

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

Не то чтобы вы писали свои собственные потоки, в Java 1.6 есть много хороших пулов потоков. Но если вы уверены, что нуждаетесь в ветке, вам нужно знать, как ее остановить.

Шаблон, который я использую для потоков:

public class Foo extends Thread {
  private volatile boolean close = false;
  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

Обратите внимание, что нет необходимости в синхронизации

 18 окт. 2016 г., 12:39
@aroth: с сегодняшними виртуальными машинами Java вы можете заметить, что на практике, даже с простейшими примерами, вы не можете & t = x2019;reliably воспроизвести это поведение. В более сложных приложениях у вас иногда есть другие действия с гарантиями видимости памяти в вашем коде, которые заставляют его работать, что особенно опасно, так как вы не знаете, почему это работает, и простое, по-видимому, несвязанное изменение в вашем коде может сломать ваше приложение & # x2026;
 03 сент. 2015 г., 16:33
Вы бы сказали, что есть преимущество между остановкой такого потока или использованием методов Thread # interrupt () и Thread # isInterrupted ()?
 06 июн. 2013 г., 20:48
@Jori, вам нужен volatile, потому что поток, читающий close в цикле while, отличается от того, который вызывает close (). Без volatile поток, выполняющий цикл, может никогда не увидеть изменения, чтобы закрыться.
 21 февр. 2016 г., 14:28
@Pyrolistical - Вы наблюдали за темойnever видя изменения на практике? Или вы можете расширить пример, чтобы надежно вызвать эту проблему? Мне любопытно, потому что я знаю, что использовал (и видел, как другие используют) код, который в основном идентичен примеру, но безvolatile Ключевое слово, и всегда кажется, что работает нормально.
 06 июн. 2013 г., 09:27
Интересно, почему это даже необходимо. Разве это не нужно, только если другие потоки должны реагировать на изменение статуса этого потока таким образом, что синхронизация потоков находится под угрозой?

страницавозникает необходимость в переменной volatile для исправления проблем с согласованностью памяти:

Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable.

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

Как объяснено вPeter Parker ответ, при отсутствииvolatile модификатор, стек каждого потока может иметь свою собственную копию переменной. Делая переменную какvolatile, проблемы согласованности памяти были исправлены.

Посмотри наjenkov учебная страница для лучшего понимания.

Посмотрите на связанный вопрос SE для получения дополнительной информации о volatile & amp; варианты использования для использования volatile:

Разница между изменчивым и синхронизированным в Java

Один практический пример использования:

У вас есть много потоков, которые необходимо напечатать текущее время в определенном формате, например:java.text.SimpleDateFormat("HH-mm-ss"), Yon может иметь один класс, который конвертирует текущее время вSimpleDateFormat и обновлял переменную каждую секунду. Все остальные потоки могут просто использовать эту переменную для печати текущего времени в файлах журнала.

Объяснение Дженкова:

The Java volatile keyword is used to mark a Java variable as "being stored in main memory". More precisely that means, that every read of a volatile variable will be read from the computer's main memory, and not from the CPU cache, and that every write to a volatile variable will be written to main memory, and not just to the CPU cache.

Actually, since Java 5 the volatile keyword guarantees more than just that volatile variables are written to and read from main memory.

Это расширенная гарантия видимости, так называемая гарантия «происходит раньше».

Performance Considerations of volatile

Reading and writing of volatile variables causes the variable to be read or written to main memory. Reading from and writing to main memory is more expensive than accessing the CPU cache. Accessing volatile variables also prevent instruction reordering which is a normal performance enhancement technique. Thus, you should only use volatile variables when you really need to enforce visibility of variables.

1 & GT; Чтение и запись изменчивых переменных различными потоками всегда осуществляется из памяти, а не из собственного кэша или регистра процессора. Таким образом, каждый поток всегда имеет дело с последним значением. 2 & GT; Когда 2 разных потока работают с одним и тем же экземпляром или статическими переменными в куче, можно видеть, что другие действия не работают. Смотрите блог Джереми Мэнсона по этому вопросу. Но волатильность помогает здесь.

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

thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3

Для достижения этой цели мы можем использовать следующий полноценный работающий код.

public class Solution {
    static volatile int counter = 0;
    static int print = 0;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Thread[] ths = new Thread[4];
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new Thread(new MyRunnable(i, ths.length));
            ths[i].start();
        }
    }
    static class MyRunnable implements Runnable {
        final int thID;
        final int total;
        public MyRunnable(int id, int total) {
            thID = id;
            this.total = total;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                if (thID == counter) {
                    System.out.println("thread " + thID + " prints " + print);
                    print++;
                    if (print == total)
                        print = 0;
                    counter++;
                    if (counter == total)
                        counter = 0;
                } else {
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        // log it
                    }
                }
            }
        }
    }
}

Следующая ссылка на github содержит файл readme, который дает правильное объяснение. https://github.com/sankar4git/volatile_thread_ordering

кроме остановки потока, в котором используется ключевое слово volatile,

Double-checked locking mechanism. Used often in Singleton design pattern. In this the singleton object needs to be declared volatile. Spurious Wakeups. Thread may sometimes wake up from wait call even if no notify call has been issued. This behavior is called supurious wakeup. This can be countered by using a conditional variable(boolean flag). Put the wait() call in a while loop as long as the flag is true. So if thread wakes up from wait call due to any reasons other than notify/notifyall then it encounters flag is still true and hence calls wait again. Prior to calling notify set this flag to true. In this case the boolean flag is declared as volatile.

йных переменных. Чтение и запись - это атомарные операции для ссылочных переменных и большинства примитивных переменных, за исключением типов переменных long и double, которые должны использовать ключевое слово volatile для атомарных операций.@ссылка на сайт

 16 июн. 2017 г., 14:27
@KaiWang вам не нужно использовать volatile для логических значений для целей атомарности. Но вы, конечно, можете по причинам видимости. Ты это хотел сказать?
 03 апр. 2017 г., 16:10
Чтобы сделать его еще более понятным, не нужно устанавливать логическое значение volatile, потому что чтение и запись логического значения УЖЕ атомарны.

Prevents JVM from reading values from register (assume as cache), and forces its value to be read from memory. Reduces the risk of memory in-consistency errors.

Prevents JVM from reading values in register, and forces its value to be read from memory.

busy flag используется для предотвращения продолжения потока, пока устройство занято и флаг не защищен блокировкой:

while (busy) {
    /* do something else */
}

Поток тестирования продолжится, когда другой поток отключитbusy flag:

busy = 0;

Тем не менее, поскольку в потоке тестирования часто осуществляется доступ к занятости, JVM может оптимизировать тест, поместив значение занятости в регистр, а затем протестировать содержимое регистра, не считывая значение занятости в памяти перед каждым тестом. Поток тестирования никогда не увидит изменения занятости, а другой поток только изменит значение занятости в памяти, что приведет к взаимоблокировке. Объявлениеbusy flag так как volatile заставляет читать значение перед каждым тестом.

Reduces the risk of memory consistency errors.

Использование изменчивых переменных снижает рискmemory consistency errorsпотому что любая запись в энергозависимую переменную устанавливает "happens-before" связь с последующими чтениями этой же переменной. Это означает, что изменения в изменчивой переменной всегда видны другим потокам.

Методика чтения, записи без ошибок согласованности памяти называетсяatomic action.

Атомное действие - это то, что эффективно происходит одновременно. Атомное действие не может остановиться в середине: оно либо происходит полностью, либо вообще не происходит. Никакие побочные эффекты атомного действия не видны, пока действие не завершено.

Ниже приведены действия, которые можно указать как атомарные:

Reads and writes are atomic for reference variables and for most primitive variables (all types except long and double). Reads and writes are atomic for all variables declared volatile (including long and double variables).

Ура!

я использую это довольно часто - это может быть очень полезно для многопоточного кода. Статья, на которую вы указали, хорошая. Хотя следует помнить о двух важных вещах:

You should only use volatile if you completely understand what it does and how it differs to synchronized. In many situations volatile appears, on the surface, to be a simpler more performant alternative to synchronized, when often a better understanding of volatile would make clear that synchronized is the only option that would work. volatile doesn't actually work in a lot of older JVMs, although synchronized does. I remember seeing a document that referenced the various levels of support in different JVMs but unfortunately I can't find it now. Definitely look into it if you're using Java pre 1.5 or if you don't have control over the JVMs that your program will be running on.

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

но и в C #.) Есть моменты, когда вам нужно получить или установить значение, которое гарантированно будет атомарной операцией на вашей данной платформе, например, int или boolean, но не требует накладные расходы на блокировку резьбы. Ключевое слово volatile позволяет вам убедиться, что когда вы читаете значение, вы получаетеcurrent значение, а не кэшированное значение, которое просто устарело при записи в другой поток.

 06 янв. 2012 г., 15:29
Исправленный. Спасибо!

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


import java.util.ArrayList;
import java.util.List;

public class Main {

    public static volatile  int a = 0;
    public static void main(String args[]) throws InterruptedException{

        List<Thread> list = new  ArrayList<Thread>();
        for(int i = 0 ; i<11 ;i++){
            list.add(new Pojo());
        }

        for (Thread thread : list) {
            thread.start();
        }

        Thread.sleep(20000);
        System.out.println(a);
    }
}
class Pojo extends Thread{
    int a = 10001;
    public void run() {
        while(a-->0){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Main.a++;
            System.out.println("a = "+Main.a);
        }
    }
}

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

    

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicInteger;

    public class Main {

        public static volatile  AtomicInteger a = new AtomicInteger(0);
        public static void main(String args[]) throws InterruptedException{

            List<Thread> list = new  ArrayList<Thread>();
            for(int i = 0 ; i<11 ;i++){
                list.add(new Pojo());
            }

            for (Thread thread : list) {
                thread.start();
            }

            Thread.sleep(20000);
            System.out.println(a.get());

        }
    }
    class Pojo extends Thread{
        int a = 10001;
        public void run() {
            while(a-->0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Main.a.incrementAndGet();
                System.out.println("a = "+Main.a);
            }
        }
    }
Решение Вопроса

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

Чтобы ответить на ваш вопрос: да, я используюvolatile переменная для управления продолжением цикла. Цикл проверяетvolatile значение и продолжается, если этоtrue, Условие может быть установлено вfalse позвонив в «Стоп» метод. Петля видитfalse и завершается, когда он проверяет значение после того, как метод stop завершает выполнение.

Книга & quot;Java-параллелизм на практике, & Quot; который я очень рекомендую, дает хорошее объяснениеvolatile, Эта книга написана тем же человеком, который написал статью IBM, на которую есть ссылка в этом вопросе (фактически, он цитирует свою книгу в нижней части этой статьи). Мое использованиеvolatile это то, что его статья называет «флагом состояния шаблона 1».

Если вы хотите узнать больше о том, какvolatile работает под капотом, читай дальшемодель памяти Java, Если вы хотите выйти за рамки этого уровня, посмотрите хорошую книгу по компьютерной архитектуре, напримерHennessy & amp; Patterson и прочитайте о согласованности и согласованности кэша.

 23 февр. 2014 г., 00:37
Статья, связанная в вопросе, имеет примеры кода.
 05 июл. 2017 г., 10:06
@fefrei: & # x201C; немедленно & # x201D; это разговорный термин. Конечно, это не может быть гарантировано, когда ни время, ни время выполнения, ни алгоритмы планирования потоков фактически не указаны. Единственный способ для программы выяснить, является ли энергозависимое чтение последующим за определенной энергозависимой записью, это проверить, является ли видимое значение ожидаемым записанным.
 22 февр. 2014 г., 07:43
Для начинающих я прошу вас продемонстрировать с помощью некоторого кода (пожалуйста?)
 18 сент. 2015 г., 19:56
Я думаю, что ссылка 'Hennessy & amp; Паттерсон & APOS; сломано. И ссылка на «модель памяти Java»; фактически приводит к тому, что Oracle описывает язык Java. Глава 17. Потоки и блокировки.
 18 июл. 2013 г., 14:32
Этот ответ правильный, но неполный. Это пропускает важное свойствоvolatile которая пришла с новой моделью памяти Java, определенной в JSR 133: когда поток читаетvolatile переменная, в которой он видит не только значение, последнее записанное в него каким-либо другим потоком, но также и все другие записи в другие переменные, которые были видны в этом другом потоке во времяvolatile написать. Увидетьthis answer а такжеthis reference.

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

Только переменная-член может быть изменчивой или переходной.

“… the volatile modifier guarantees that any thread that reads a field will see the most recently written value.” - Josh Bloch

Если вы думаете об использованииvolatileпрочитайте на упаковкеjava.util.concurrent который имеет дело с атомным поведением.

Википедия пост наСинглтон показывает изменчивость в использовании.

 28 мар. 2014 г., 09:19
Цитата действительно доводит это до сути.
 09 мая 2015 г., 04:32
Почему там обаvolatile а такжеsynchronized ключевые слова?
 23 сент. 2016 г., 14:26
С тех пор статья в Википедии, посвященная шаблону синглтона, сильно изменилась, и в ней ничего не сказано.volatile Пример уже не так. Можно найтиin an archived version.

volatile.

// Code to prove importance of 'volatile' when state of one thread is being mutated from another thread.
// Try running this class with and without 'volatile' for 'state' property of Task class.
public class VolatileTest {
    public static void main(String[] a) throws Exception {
        Task task = new Task();
        new Thread(task).start();

        Thread.sleep(500);
        long stoppedOn = System.nanoTime();

        task.stop(); // -----> do this to stop the thread

        System.out.println("Stopping on: " + stoppedOn);
    }
}

class Task implements Runnable {
    // Try running with and without 'volatile' here
    private volatile boolean state = true;
    private int i = 0;

    public void stop() {
        state = false;
    } 

    @Override
    public void run() {
        while(state) {
            i++;
        }
        System.out.println(i + "> Stopped on: " + System.nanoTime());
    }
}

When volatile is not used: ты никогда не увидишьStopped on: xxx& APOS; сообщение даже после & apos;Stopping on: xxxи программа продолжает работать.

Stopping on: 1895303906650500

When volatile used: вы увидите "Stopped on: xxx& APOS; немедленно.

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300

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

Если вы разрабатываете приложение, которое будет развернуто на сервере приложений (Tomcat, JBoss AS, Glassfish и т. Д.), Вам не придется самостоятельно управлять управлением параллелизмом, как это уже выполняется сервером приложений. На самом деле, если я правильно помню, стандарт Java EE запрещает какой-либо контроль параллелизма в сервлетах и EJB-компонентах, поскольку он является частью «инфраструктуры». слой, который вы должны были освободить от обработки. Вы управляете параллелизмом в таком приложении, только если вы реализуете одноэлементные объекты. Это даже уже решено, если вы связываете свои компоненты, используя frameworkd, как Spring.

Таким образом, в большинстве случаев разработки Java, когда приложение является веб-приложением и использует IoC-фреймворк, такой как Spring или EJB, вам не нужно использовать «volatile».

Volatile variable изменяется асинхронно путем одновременного запуска потоков в приложении Java. Не разрешается иметь локальную копию переменной, которая отличается от значения, которое в настоящее время хранится в «main». объем памяти. По сути, переменная, объявленная volatile, должна синхронизировать свои данные во всех потоках, чтобы при каждом обращении к переменной или ее обновлении в любом потоке все остальные потоки сразу видели одно и то же значение. Конечно, вполне вероятно, что изменчивые переменные имеют более высокие издержки доступа и обновления, чем & quot; plain & quot; переменные, потому что потоки причины могут иметь свою собственную копию данных для лучшей эффективности.

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

для справки, обратитесь к этомуhttp://techno-terminal.blogspot.in/2015/11/what-are-volatile-variables.html

volatile Ключевое слово, имеет два основных качества, которые делают его особенным.

If we have a volatile variable, it cannot be cached into the computer's(microprocessor) cache memory by any thread. Access always happened from main memory.

If there is a write operation going on a volatile variable, and suddenly a read operation is requested, it is guaranteed that the write operation will be finished prior to the read operation.

Два вышеперечисленных качества выводят, что

All the threads reading a volatile variable will definitely read the latest value. Because no cached value can pollute it. And also the read request will be granted only after the completion of the current write operation.

И с другой стороны,

If we further investigate the #2 that I have mentioned, we can see that volatile keyword is an ideal way to maintain a shared variable which has 'n' number of read threads and only one write thread to access it. Once we add the volatile keyword, it is done. No any other overhead about thread safety.

Conversly,

Мыcan't использоватьvolatile ключевое слово исключительно для удовлетворения общей переменной, которая имеетmore than one write threads accessing it.

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

Если изменения выполняются одним потоком, а остальным нужно просто прочитать это значение, подойдет volatile.

Ваш ответ на вопрос