Модель java meomry предусматривает, что блоки synchronize
, которые синхронизируются на одном мониторе, применяют до-после-realtion переменные, модифицированные в этих блоках. Пример:Модель памяти Java: переупорядочение и параллельные блокировки
// in thread A
synchronized(lock)
{
x = true;
}
// in thread B
synchronized(lock)
{
System.out.println(x);
}
В этом случае она Гарантированная, что поток В будет видеть x==true
тех пор, пока нить А уже прошел, что synchronized
-блока. Теперь я перерабатываю много кода, чтобы использовать более гибкие (и считающиеся более быстрыми) блокировки в java.util.concurrent
, особенно ReentrantReadWriteLock
. Так пример выглядит следующим образом:
EDIT: пример был сломан, потому что я неправильно преобразовал код, как отметил матового б. Фиксированный следующим образом:
// in thread A
lock.writeLock().lock();
{
x = true;
}
lock.writeLock().unlock();
// in thread B
lock.readLock().lock();
{
System.out.println(x);
}
lock.readLock().unlock();
Однако, я не видел никаких намеков в пределах спецификации модели памяти, что такие замки также подразумевают nessessary упорядочения. Рассматривая реализацию, она полагается на доступ к изменчивым переменным внутри AbstractQueuedSynchronizer
(для реализации солнца как минимум). Однако это не является частью какой-либо спецификации, и, кроме того, доступ к энергонезависимым переменным на самом деле не учитывается защитой памяти, определяемой этими переменными, не так ли?
Итак, вот мои вопросы:
- Безопасно предположить тот же порядок, как с «старых»
synchronized
блоков? - Является ли это документированным где-то?
- Доступ к любой изменчивой переменной является барьером памяти для любой другой переменной?
С уважением, Штеффен
-
Комментарий к Yanamon:
Посмотрите на следующий код:
// in thread a
x = 1;
synchronized (a) { y = 2; }
z = 3;
// in thread b
System.out.println(x);
synchronized (a) { System.out.println(y); }
System.out.println(z);
Из того, что я понял, барьер памяти навязывает второй вывод для отображения 2, но не оказывает гарантированного влияния на другие переменные ...? Итак, как это можно сравнить с доступом к изменчивой переменной?
Одна заметка о добавленном вами коде, поток b будет печатать только 2, если он получает блокировку перед потоком a ... это было своего рода подразумеваемым, но я просто хотел сделать это понятным. Но для ответа на ваш неустойчивый вопрос, volatile будет использоваться следующим образом для обеспечения видимости: -------- volatile boolean memoryBarrier = false; int unguardedValue = 0; // thread a: unguardedValue = 10; memoryBarrier = true; // thread b if (memoryBarrier) { // unguardedValue гарантированно считается 10; } – Yanamon
Ну, я думаю, что писать код в комментариях не очень хорошо, я обновил свой ответ на примере – Yanamon