Это технически ориентировано на многопотоковое исполнение несмотря на то, чтобы быть изменяемым?

Да, переменная члена парламента, не занимающего официального поста bar должен быть final правильно? Но на самом деле, в этом экземпляре, это - атомарная операция для простого чтения значения int. Таким образом, это технически ориентировано на многопотоковое исполнение?

class Foo {
    private int bar;
    public Foo(int bar) {
        this.bar = bar;
    }
    public int getBar() {
        return bar;
    }
}

//примите бесконечное число потоков, неоднократно звоня getBar на том же экземпляре Foo.

Править:

Предположите, что это - весь код для Foo класс; любые потоки со ссылкой на a Foo экземпляр не сможет изменить значение bar (не идя в такие длины как использование отражения и т.д.)

8
задан Finbarr 5 May 2010 в 10:00
поделиться

1 ответ

Окончательное обновление: так что мой первый вывод оказался правильным, просто мои рассуждения были ошибочными :-( Я отредактировал свой ответ, чтобы сделать его несколько связным, а не скрывать следы моей предыдущей ошибки.

] Заключение

Как заметил @Wyzard, даже несмотря на то, что нет возможности изменить bar после построения, Foo по-прежнему не является потокобезопасным.Проблема не в атомарности, а в видимости. Если поток 1 изменяет значение bar в конструкторе (со значения по умолчанию 0), нет гарантии, когда другие потоки увидят новое значение (или увидят ли они его вообще ).

Итак foo выглядит как неизменяемый объект. Цитата из Java Concurrency in Practice , раздел 3.4:

Объект является неизменяемым, если:

  • Его состояние не может быть изменено после построения;
  • Все его поля являются окончательными; и
  • Он правильно сконструирован (ссылка this не исчезает во время построения).

Foo l выглядит нормально по 1) и 3), но не по 2). И это ключевой момент в связи с приведенными выше рассуждениями. Объявление переменной final - это один из способов обеспечить ее видимость между разными потоками. Другие средства - это объявление bar volatile или синхронизация его метода (ов) доступа. Но, конечно, в случае неизменяемого объекта ни то, ни другое не имело бы особого смысла.

Final Fields

Так почему же поля final гарантируют видимость? Ответ от Java Concurrency in Practice, раздел 3.5.2:

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

С другой стороны, к неизменяемым объектам можно безопасно обращаться , даже если синхронизация не используется для публикации ссылки на объект . Для сохранения этой гарантии безопасности инициализации должны быть выполнены все требования неизменяемости: немодифицируемое состояние, все поля final и правильное построение. [...]

Неизменяемые объекты могут безопасно использоваться любым потоком без дополнительной синхронизации, даже если синхронизация не используется для их публикации.

Эта гарантия распространяется на значения всех полей final правильно построенных объектов; К полям final можно безопасно обращаться без дополнительной синхронизации. Однако, если поля final относятся к изменяемым объектам, синхронизация по-прежнему требуется для доступа к состоянию объектов, на которые они ссылаются.

А что будет, если поле не окончательное? Другие потоки могут незаметно видеть устаревшее значение поля. Нет никаких исключений или предупреждений - это одна из причин, почему такие ошибки так сложно отследить.

7
ответ дан 5 December 2019 в 21:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: