Важливий момент про volatile
:
- Синхронізація в Java можна за допомогою Java ключових слів
synchronized
і volatile
і замки.
- У Java ми не можемо мати
synchronized
змінну. Використання synchronized
ключового слова зі змінною є незаконним і призведе до помилки компіляції. Замість використання synchronized
змінної в Java, ви можете використовувати volatile
змінну java , яка доручить потокам JVM зчитувати значення volatile
змінної з основної пам'яті та не кешувати її локально.
- Якщо змінна не поділяється між декількома потоками, тоді не потрібно використовувати
volatile
ключове слово.
джерело
Приклад використання 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
, не зможе передавати інший потік. Отже, якщо Thread A створює екземпляр Singleton і відразу після створення CPU псується тощо, всі інші потоки не зможуть побачити значення _instance
як недійсне, і вони вважатимуть, що це все-таки присвоєно нулю.
Чому це відбувається? Оскільки потоки читачів не роблять жодного блокування і поки потік запису не вийде із синхронізованого блоку, пам'ять не буде синхронізована, і значення _instance
не буде оновлено в основній пам'яті. З ключовим словом Volatile на Java цим керує сама Java, і такі оновлення будуть видимі в усіх потоках читачів.
Висновок : 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 () повертає об'єкт, який, можливо, не був ініціалізований повністю. Щоб зробити нитку коду безпечною, ключове слово мінливе може використовуватися з Java 5 для змінної екземпляра. Змінні, позначені як мінливі, стають видимими лише для інших потоків після того, як конструктор об'єкта закінчив його виконання повністю.
Джерело
volatile
використання на Java :
Ітератори виходу з ладу, як правило, реалізуються за допомогою volatile
лічильника на об'єкті списку.
- Коли список оновлюється, лічильник збільшується.
- Коли
Iterator
створюється, поточне значення лічильника вбудовується в Iterator
об'єкт.
- Коли
Iterator
виконується операція, метод порівнює два значення лічильника і кидає a, ConcurrentModificationException
якщо вони різні.
Запровадження ітераторів безвідмовної роботи, як правило, мало важить. Вони, як правило, покладаються на властивості структур даних конкретної реалізації списку. Загальної закономірності немає.
volatile
цієї функції з новою моделлю пам'яті Java, визначеною в JSR 133: що, коли нитка читаєvolatile
змінну, вона бачить не тільки значення, останнє, записане до неї іншим потоком, а й усі інші записи в інші змінні, які були помітні в тій іншій нитці під часvolatile
написання. Дивіться цю відповідь та цю посилання .