Почему `synchronized (new Object ()) {}` не работает?

В следующем коде:

class A {
    private int number;

    public void a() {
        number = 5;
    }

    public void b() {
        while(number == 0) {
            // ...
        }
    }
}

Если вызывается метод b, а затем запускается новый поток, который запускает метод a, то гарантируется, что метод b никогда не увидит измененияnumber и поэтомуb никогда не может прекратить.

Конечно, мы могли бы сделатьnumber volatile чтобы решить это. Однако по академическим причинам давайте предположим, чтоvolatile не вариант:

JSR-133 часто задаваемые вопросы говорит нам:

После выхода из синхронизированного блока мы отпускаем монитор, которыйимеет эффект сброса кеша в основную память, так что записи, сделанные этим потоком, могут быть видны другим потокам. Прежде чем мы сможем войти в синхронизированный блок, мы приобретаем монитор, которыйимеет эффект аннулирования кэша локального процессора так что переменные будут перезагружены из основной памяти.

Звучит так, будто мне нужны обаa а такжеb входить и выходить из любогоsynchronized-Блок вообще, независимо от того, какой монитор они используют. Точнее это звучит так ...:

class A {
    private int number;

    public void a() {
        number = 5;
        synchronized(new Object()) {}
    }

    public void b() {
        while(number == 0) {
            // ...
            synchronized(new Object()) {}
        }
    }
}

... устранит проблему и гарантирует, чтоb увидим изменениеa и, таким образом, также в конечном итоге прекратится.

Однако часто задаваемые вопросы также ясно заявляют:

Другим следствием является то, что следующий шаблон, который некоторые люди используют для создания барьера памяти, не работает:

synchronized (new Object()) {}

На самом деле это не работает, и ваш компилятор может полностью удалить его, потому что компилятор знает, что никакой другой поток не будет синхронизироваться на том же мониторе. Вы должны установить отношение «до и после» для одного потока, чтобы увидеть результаты другого.

Теперь это сбивает с толку. Я думал, что синхронизированный оператор вызовет сброс кешей. Конечно, он не может сбросить кэш в основную память таким образом, чтобы изменения в основной памяти могли видеть только потоки, которые синхронизируются на одном мониторе, тем более что для volatile, который в основном делает то же самое, нам даже не нужен монитор, или я там ошибаюсь? Так почему же это неоперация и не вызываетb расторгнуть по гарантии?

Ответы на вопрос(2)

Ваш ответ на вопрос