Итак, я только что узнал о ключевом слове 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 делает вывод не таким «стабильным», как при отсутствии ключевого слова.