#java #concurrency #synchronization #volatile
#java #параллелизм #синхронизация #изменчивая
Вопрос:
Я где-то читал, что процессоры x86 обладают когерентностью кэша и в любом случае могут синхронизировать значения полей на нескольких ядрах при каждой записи.
Означает ли это, что мы можем кодировать без использования ‘volatile’ keywoard в java, если планируем работать только на процессорах x86?
Обновить:
Хорошо, предполагая, что мы не учитываем проблему переупорядочения команд, можем ли мы предположить, что проблема присвоения энергонезависимому полю, невидимому для разных ядер, отсутствует на процессорах x86?
Комментарии:
1. Поддерживает ли Java DMA (например, для приводов компакт-дисков и ввода-вывода с привязкой к памяти)?
2. Зачем вам это? Просто используйте ее в любом случае.
3. Что, если у вас несколько процессоров?
Ответ №1:
Нет — volatile
ключевое слово имеет большее значение, чем просто согласованность кэша; оно также накладывает ограничения на то, что может и не может делать среда выполнения, например, на задержку вызовов конструктора.
Комментарии:
1. В частности, как Hotspot разрешено оптимизировать ваш код при компиляции его в машинный код.
Ответ №2:
О вашем обновлении: Нет, мы не можем. Другие потоки могут просто считывать устаревшие значения без обновления переменной. И еще одна проблема: JVM разрешено оптимизировать код до тех пор, пока она может гарантировать, что однопоточное поведение является правильным.
Это означает, что что-то вроде:
public boolean var = true;
private void test() {
while (var) {
// do something without changing var
}
}
может быть оптимизирована JIT в while (true), если захочет!
Ответ №3:
Между can sync the value of fields
и always syncs the value of fields
существует большая разница. x86 может синхронизировать поля, если у вас есть volatile, в противном случае это не так и не должно быть.
Примечание: изменяемый доступ может быть в 10-30 раз медленнее, чем энергонезависимый доступ, что является ключевой причиной, по которой это выполняется не всегда.
Кстати: знаете ли вы какие-либо многоядерные, простые процессоры x86. Я бы подумал, что большинство из них — x64 с поддержкой x86.
Комментарии:
1. есть ли у вас какие-либо тесты / примеры этой 10-30-кратной медлительности? Я использовал volatile для переменных, которые считываются огромное количество раз, практически без разницы в производительности между изменчивыми и энергонезависимыми версиями.
2. Разница в производительности невелика, если вы обращаетесь к полю только в одном потоке. Однако она намного больше, когда поле совместно используется потоками. Т.е. кэш довольно умен. Вы агрессивно распределяете поле между потоками?
3. Я вижу, что энергозависимый доступ занимает 26 нс, тогда как энергонезависимый доступ занимает 2 нс. Проблема в том, чтобы избежать ошибок микро-тестов, которые могут свести все практически к нулю. 😉
4. когда вы говорите access, вы имеете в виду хранилища / загрузки или и то, и другое. Изменчивая нагрузка на систему cache coherent system очень близка к нормальной нагрузке.
5. @John V, я обнаружил, что очень многое зависит от архитектуры системы. Загрузка для доступа к устаревшему значению и загрузка для доступа к значению, которое не является устаревшим, как правило, сильно отличаются.
Ответ №4:
Существуют очень точные спецификации того, как должна вести себя JVM для volatile
, и если она решит сделать это с использованием инструкций, специфичных для процессора, то это хорошо для вас.
Единственное место, где вы должны сказать «мы знаем, что на этой платформе процессор ведет себя как ..», — это при компоновке в машинном коде, где он должен соответствовать процессору. Во всех остальных случаях пишите в спецификацию.
Обратите внимание, что ключевое слово volatile очень важно для написания надежного кода, работающего на нескольких процессорах, каждый из которых имеет свой собственный кэш, поскольку оно сообщает JVM игнорировать локальный кэш и получать официальное значение вместо кэшированного значения 5-минутной давности. Обычно вы этого хотите.
Ответ №5:
запись в байт-коде даже не обязательно должна вызывать запись в машинный код. если только это не изменчивая запись.
Ответ №6:
Я могу поручиться за volatile
то, что она имеет некоторое применение. Я был в ситуации, когда один поток имеет ‘null’ для переменной, а другой имеет правильное значение для переменной, которая была установлена в этом потоке. Отлаживать ее неинтересно. Используйте изменчивую для всех общих полей 🙂