Причина, по которой ничего не происходит без System.out.println("here");
, объясняется ответом Камерона Скиннера.
Так почему же блок внутри if(x!=0)
работает, когда используется println
? println
выполняет блок synchronized
(см. PrintStream.write(String s)
). Это заставляет текущий поток извлекать состояние System.out
из основной памяти и обновлять кеш потока, прежде чем позволить потоку выполнить любую дальнейшую строку кода.Неожиданным побочным эффектом является то, что также сохраняются состояния других переменных, таких как ваш x
, но блокировка x
не включалась в синхронизацию. Это называется с помидорами.
Если я буду использовать свободный текст, чтобы описать формальности, описанные в Java Memory Model Specification: он говорит, что операции выполняются до того, как выпуск замка произойдет, перед тем операций выполняются после очередного получения этого замка.
Я продемонстрирую это на примере. Предположим, что выполняется Thread 1
, и только когда он заканчивается, начинается Thread 2
. Также предположим, что x
, y
и z
являются переменными, разделяемыми обоими потоками. Обратите внимание, что мы можем определить значение z
только внутри блока synchronized
y
.
Thread 1:
x = 0;
synchronized(y) {
}
Thread 2:
x = 1
z = x;
// here there's no guarantee as to z value, could be 0 or 1
synchronized(y) {
z = x;
// here z has to be 0!
}
Это, конечно, очень плохая практика полагаться на синхронизацию ...
'x' является INT? или любой объект-обертку? – Vaandu
просто FYI, и вы можете это знать уже: вы можете сделать 'while (true)', если вы хотите, чтобы цикл while был всегда запущен. – Joel
x является char и принадлежит объекту X. В свою очередь, X является статическим членом класса. Я понимаю, что это не лучший способ сделать это для моих целей, но я был удивлен результатами. – Ivan