Эта программа не завершается!
public class Main extends Thread {
private int i = 0;
private int getI() {return i; }
private void setI(int j) {i = j; }
public static void main(String[] args) throws InterruptedException {
Main main = new Main();
main.start();
Thread.sleep(1000);
main.setI(10);
}
public void run() {
System.out.println("Awaiting...");
while (getI() == 0) ;
System.out.println("Done!");
}
}
Я понимаю, что это происходит потому, что ядро ЦП, работающее в цикле Awaiting
, всегда видит кэшированную копию i
и пропускает обновление.
Я также понимаю, что если я сделаю volatile
private int i = 0;
, тогда while (getI()...
будет вести себя [1] , как будто каждый раз, когда он обращается к основной памяти - так он увидит обновленное значение и моя программа прекратит работу.
Мой вопрос: Если я сделаю
synchronized private int getI() {return i; }
Это удивительно работает !! Программа завершается.
Я понимаю, что synchronized
используется для предотвращения одновременного входа в метод двух разных потоков, но здесь только один поток, который когда-либо входит в getI()
. Так что это за колдовство?
Редактировать 1
Это (синхронизация) гарантирует, что изменения состояния объекта видны всем потокам
Таким образом, вместо того, чтобы напрямую иметь поле частного состояния i
, я сделал следующие изменения:
Вместо private int i = 0;
Я сделал private Data data = new Data();
, i = j
изменен на data.i = j
и return i
изменен на return data.i
Теперь методы getI
и setI
ничего не делают для состояния объекта, в котором они определены (и могут быть синхронизированы). Даже сейчас использование ключевого слова synchronized
приводит к завершению программы! Самое интересное в том, что у объекта, состояние которого действительно изменяется (Data
), нет синхронизации или чего-либо встроенного в него. Тогда почему?
[1] Это, вероятно, будет просто вести себя , поскольку то, что на самом деле происходит, мне неясно