logo

Volatile Keyword в Java

Ключове слово volatile використовується для зміни значення змінної різними потоками. Він також використовується, щоб зробити класи потокобезпечними. Це означає, що кілька потоків можуть використовувати метод і екземпляр класів одночасно без будь-яких проблем. Ключове слово volatile можна використовувати або з примітивним типом, або з об’єктами.

Ключове слово volatile не кешує значення змінної та завжди читає змінну з основної пам’яті. Ключове слово volatile не можна використовувати з класами або методами. Однак він використовується зі змінними. Це також гарантує видимість і порядок. Це запобігає компілятору змінювати порядок коду.

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

приклад

 class Test { static int var=5; } 

У наведеному вище прикладі припустимо, що два потоки працюють над одним класом. Обидва потоки працюють на різних процесорах, де кожен потік має свою локальну копію var. Якщо будь-який потік змінює своє значення, ця зміна не відобразиться на вихідному в основній пам’яті. Це призводить до неузгодженості даних, оскільки інший потік не знає про змінене значення.

 class Test { static volatile int var =5; } 

У наведеному вище прикладі статичні змінні є членами класу, які є спільними для всіх об’єктів. В основній пам'яті є лише одна копія. Значення мінливої ​​змінної ніколи не зберігатиметься в кеші. Усе читання та запис виконуватиметься з основної пам’яті та до неї.

Коли це використовувати?

  • Ви можете використовувати змінну volatile, якщо хочете автоматично читати та записувати змінну long і double.
  • Його можна використовувати як альтернативний спосіб досягнення синхронізації в Java.
  • Усі потоки читачів побачать оновлене значення змінної volatile після завершення операції запису. Якщо ви не використовуєте ключове слово volatile, різні потоки читачів можуть бачити різні значення.
  • Він використовується для інформування компілятора про те, що кілька потоків отримають доступ до певного оператора. Це перешкоджає компілятору виконувати будь-яке перевпорядкування чи оптимізацію.
  • Якщо ви не використовуєте змінну volatile, компілятор може змінити порядок коду, вільно записуючи в кеш значення змінної volatile замість читання з основної пам’яті.

Важливі моменти

  • Ви можете використовувати ключове слово volatile зі змінними. Використання ключового слова volatile із класами та методами є незаконним.
  • Це гарантує, що значення змінної volatile завжди читатиметься з основної пам’яті, а не з кешу локального потоку.
  • Якщо ви оголосили змінну як volatile, читання та запис є атомарними
  • Це зменшує ризик помилки узгодженості пам’яті.
  • Будь-який запис до змінної volatile у Java встановлює подію перед взаємозв’язком із послідовними читаннями тієї самої змінної.
  • Volatile змінні завжди видимі для інших потоків.
  • Volatile змінна, яка є посиланням на об’єкт, може бути нульовою.
  • Якщо змінна не є спільною для кількох потоків, вам не потрібно використовувати ключове слово volatile із цією змінною.

Різниця між ключовим словом синхронізації та volatile

Ключове слово volatile не є заміною синхронізованого ключового слова, але в деяких випадках його можна використовувати як альтернативу. Існують такі відмінності:

Непостійне ключове слово Ключове слово синхронізації
Ключове слово volatile є модифікатором поля. Ключове слово Synchronized змінює блоки коду та методи.
Потік не може бути заблокований для очікування у випадку volatile. Потоки можуть бути заблоковані для очікування у разі синхронізації.
Це покращує продуктивність потоку. Синхронізовані методи погіршують продуктивність потоку.
Він синхронізує значення однієї змінної за раз між пам’яттю потоків і основною пам’яттю. Він синхронізує значення всіх змінних між пам'яттю потоків і основною пам'яттю.
Volatile поля не підлягають оптимізації компілятора. Синхронізація підлягає оптимізації компілятора.

Приклад Volatile Keyword

У наступному прикладі ми визначили клас, який збільшує значення лічильника. Метод run () у VolatileThread.java отримує оновлене та старе значення, коли потік починає виконуватися. У основному класі ми визначаємо масив потоків.

VolatileData.java

 public class VolatileData { private volatile int counter = 0; public int getCounter() { return counter; } public void increaseCounter() { ++counter; //increases the value of counter by 1 } } 

VolatileThread.java

 VolatileThread.java public class VolatileThread extends Thread { private final VolatileData data; public VolatileThread(VolatileData data) { this.data = data; } @Override public void run() { int oldValue = data.getCounter(); System.out.println('[Thread ' + Thread.currentThread().getId() + ']: Old value = ' + oldValue); data.increaseCounter(); int newValue = data.getCounter(); System.out.println('[Thread ' + Thread.currentThread().getId() + ']: New value = ' + newValue); } } 

VolatileMain.java

 public class VolatileMain { private final static int noOfThreads = 2; public static void main(String[] args) throws InterruptedException { VolatileData volatileData = new VolatileData(); //object of VolatileData class Thread[] threads = new Thread[noOfThreads]; //creating Thread array for(int i = 0; i <noofthreads; ++i) threads[i]="new" volatilethread(volatiledata); for(int i="0;" < noofthreads; threads[i].start(); starts all reader threads threads[i].join(); wait for } pre> <p> <strong>Output:</strong> </p> <pre> [Thread 9]: Old value = 0 [Thread 9]: New value = 1 [Thread 10]: Old value = 1 [Thread 10]: New value = 2 </pre> <hr></noofthreads;>