Java удаляет / оптимизирует ненужные синхронизированные операторы? - PullRequest
10 голосов
/ 13 августа 2011

Давайте представим, что кто-то синхронизирует метод, возвращающий int:

int whatever = 33;
...

public synchronized int getWathever() {
    return this.whatever;
}

Мы знаем из спецификаций Java, что целые изменяются атомарно. Следовательно, оператор synchronized не обязателен.

Будут ли компиляторы удалять / оптимизировать его?

Ответы [ 4 ]

7 голосов
/ 13 августа 2011

synchronized имеет другие эффекты безопасности потока, кроме получения блокировки (гарантируя, что измененные данные видны другим потокам для одного)

до тех пор, пока эти побочные эффекты действительны, JIT по существу свободен делать то, что хочет

хотя в этом примере он должен гарантировать, что блокировка не удерживается никаким другим потоком во время загрузки переменной, что проще всего обеспечить путем эффективного получения блокировки

7 голосов
/ 13 августа 2011

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

В частности, порядок синхронизации порядок, указанный в спецификации языка Java, будет нарушен.Если компилятор или JVM * должны были удалить любые «нежелательные» синхронизации, то любая дальнейшая оптимизация нарушила бы любые предположения, сделанные разработчиком в отношении порядка синхронизации (и случая до).В вашем конкретном случае любая запись в целое число произойдет до чтения в компиляторе / JVM, который подчиняется модели памяти Java.

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

* Обратите внимание, ссылка на компилятор / JVM duo является преднамеренной.Компилятор будет генерировать только байт-код, соответствующий JLS;JVM может просто иметь ошибку, из-за которой требования модели памяти все еще могут быть нарушены.Для полноты модели памяти и компилятор, и JVM должны соответствовать требованиям, установленным моделью памяти.

5 голосов
/ 13 августа 2011

Бывают случаи, когда ВМ может снять блокировку. Например

Анализ побега

int bar()
    Foo foo = new Foo();
    return foo.getWhatever();

ВМ может привести к тому, что foo не виден никакому другому потоку, поэтому никто другой не будет пытаться его заблокировать, поэтому блокировка метода getWhatever может быть снята.

Блокировка огрубления

Foo foo = ...;
void bar()
    a();
    foo.getWhatever();
    b();
    foo.getWhatever();
    c();

может быть юридически объединен, чтобы сохранить одно блокирующее действие

void bar()
    synchronized(foo)
        a();
        foo.getWhatever_without_lock();
        b();
        foo.getWhatever_without_lock();
        c();

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

4 голосов
/ 13 августа 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...