Я хотел бы понять, что происходит с точки зрения кеша (протокол MESI), если программист забыл добавить ключевое слово volatile
в переменную, используемую для синхронизации.Неработающая синхронизация без изменчивой переменной
Следующий фрагмент кода просто останавливается после нескольких итераций. Я знаю, что это потому, что один из 2 потоков (предположим, THREAD 0) не видит обновление, сделанное переменной current
THREAD 1, сделанное getNext(), поэтому оно продолжает цикл навсегда.
Однако я не понимаю, почему это так. THREAD 0 зацикливается на current
и в какой-то момент должен увидеть, что линия кэша была обновлена THREAD 1 (линия кэша переключена на Модифицированное состояние) и выдает сообщение «Чтение» на шине памяти, чтобы извлечь ее в свой локальный кеш. Добавляя модификатор volatile
в переменную current
, все будет работать нормально.
Что происходит с тем, чтобы предотвратить РЕЗЬБО 0 продолжить выполнение?
Ссылка: Memory Barriers: a Hardware View for Software Hackers
public class Volatile {
public static final int THREAD_0 = 0;
public static final int THREAD_1 = 1;
public static int current;
public static int counter = 0;
public static void main(String[] args) {
current = 0;
/** Thread 0 **/
Thread thread0 = new Thread(() -> {
while(true) { /** THREAD_0 */
while (current != THREAD_0);
counter++;
System.out.println("Thread0:" + counter);
current = getNext(THREAD_0);
}
});
/** Thread 1 **/
Thread thread1 = new Thread(() -> {
while(true) { /** THREAD_1 */
while (current != THREAD_1);
counter++;
System.out.println("Thread1:" + counter);
current = getNext(THREAD_1);
}
});
thread0.start();
thread1.start();
}
public static int getNext(int threadId) {
return threadId == THREAD_0 ? THREAD_1 : THREAD_0;
}
}
Вы совершенно правы, эта проблема связана с JIT компилятором. Запуск программы только в интерпретируемом режиме (-Xint) заставит работать отлично навсегда, тогда как в скомпилированном режиме (-Xcomp) он просто не работает. Спасибо за этот ответ! –