В следующем коде:
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
-Block вообще, независимо от того, какой монитор они используют. Точнее, это звучит так:
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()) {}
Это фактически не-op, и ваш компилятор может полностью удалить его, потому что компилятор знает, что ни один другой поток не будет синхронизироваться тот же монитор. Вы должны установить связь между событиями и один поток, чтобы увидеть результаты другого.
Теперь это сбивает с толку. Я думал, что синхронизированный оператор вызовет сброс кешей. Конечно, он не может очистить кеш от основной памяти так, что изменения в основной памяти могут отображаться только потоками, которые синхронизируются на одном мониторе, тем более что для volatile, который в основном делает то же самое, нам даже не нужно монитор, или я ошибаюсь там? Итак, почему это не-op и не вызывает b
завершение гарантии?