Компилятор javac
работает почти без оптимизаций.
Собственный JIT-компилятор может переупорядочивать инструкции в случае проблем с упорядочением памяти. Однако ЦП также может переупорядочивать инструкции и обновления памяти, которые имеют тот же эффект.
Что достигается путем предоставления этой свободы компилятору?
Основным преимуществом является переносимость кода. Чем больше гарантий вы предоставите, тем труднее будет убедиться, что каждая платформа действительно делает это.
Существует также значительное улучшение производительности, позволяющее процессору выполнять инструкции как и когда это возможно, а не в строгом порядке.
Действительно ли возможно, чтобы компилятор генерировал код, который более эффективен при перестройке кода?
Да. но переупорядочение, выполняемое ЦП, является более значительным.
Мне еще предстоит увидеть практическое обоснование для этого. Иногда я чувствую, что выгоды, если таковые имеются, значительно перевешиваются рисками параллелизма, которые это может принести.
Есть ли какой-нибудь способ, которым программист может сказать компилятору не переставлять строки таким образом?
Именно поэтому вы используете барьеры памяти, такие как volatile
, synchronized
блоки и Lock
. При их использовании вы получаете гарантии безопасности нитей.
Я знаю, что использование примитивов синхронизации эффективно справляется с побочными эффектами перестановки, но я спрашиваю, есть ли прямой способ (опция компилятора), чтобы отключить это?
Вы можете отключить JIT, но большая часть переупорядочения выполняется процессором, поэтому он не достигнет многого.
Избегание переупорядочения обновлений - это небольшая часть проблемы безопасности потоков (самая большая проблема заключается в том, что она неясна и редко возникает, что затрудняет ее тестирование). И как только вы пишете код, безопасный для потоков, это облегчается.