Итак, я только что узнал о ключевом слове volatile, когда писал несколько примеров для раздела, который я буду проводить завтра. Я написал небольшую программу, чтобы продемонстрировать, что операции ++ и - не атомарны.
public class Q3 {
private static int count = 0;
private static class Worker1 implements Runnable{
public void run(){
for(int i = 0; i < 10000; i++)
count++; //Inner class maintains an implicit reference to its parent
}
}
private static class Worker2 implements Runnable{
public void run(){
for(int i = 0; i < 10000; i++)
count--; //Inner class maintains an implicit reference to its parent
}
}
public static void main(String[] args) throws InterruptedException {
while(true){
Thread T1 = new Thread(new Worker1());
Thread T2 = new Thread(new Worker2());
T1.start();
T2.start();
T1.join();
T2.join();
System.out.println(count);
count = 0;
Thread.sleep(500);
}
}
}
Как и ожидалось, вывод этой программы обычно выглядит примерно так:
-1521
-39
0
0
0
0
0
0
Однако, когда я меняю:
private static int count = 0;
на
private static volatile int count = 0;
, мой вывод меняется на:
0
3077
1
-3365
-1
-2
2144
3
0
-1
1
-2
6
1
1
Я прочитал Когда именно вы используете ключевое слово volatile в Java? поэтому я чувствую, что у меня есть базовое представление о том, что это ключевое слово делает (поддерживать синхронизацию между кэшированными копиями переменной в разных потоках, но небезопасно для чтения-обновления-записи) . Я понимаю, что этот код, конечно, не потокобезопасен. В частности, это небезопасно служить примером для моих студентов. Однако мне любопытно, почему добавление ключевого слова volatile делает вывод не таким «стабильным», как когда ключевое слово отсутствует.