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

Безопасен ли класс с синхронизированной записью в логическую переменную экземпляра? Например.:

boolean foo = true;

public synchronized void setFoo(boolean foo) {
  this.foo = foo;
}

public boolean getFoo() {
  return foo;
}

Рассматривали ли вы AtomicBoolean, чтобы развеять все сомнения?

stdunbar 08.05.2024 15:59

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

Scott McDiggles 08.05.2024 16:04

В принципе, нет, это не работает. Если вас не волнует чтение памяти, то синхронизация, которую вы используете, ничего не дает. А если вас это волнует, то вам необходимо синхронизировать и то, и другое. Компилятор должен знать, что он не может оптимизировать чтение в регистр или что-то подобное, значение необходимо перечитать.

markspace 08.05.2024 16:14
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
3
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Нет, не потокобезопасный.

Вы не учли проблему наглядности.

Изменения примитива boolean не обязательно видны во всех потоках. Из-за особенностей работы современных процессоров, оптимизации, выполненной JIT компилятором и Моделью памяти Java, один поток может не видеть изменения, внесенные другим потоком.

volatile

Один из способов решения проблемы видимости — пометить примитивную переменную boolean как volatile.

AtomicBoolean

Другой способ — заменить объект AtomicBoolean вместо примитива boolean. Отметьте переменную AtomicBoolean как final, чтобы предотвратить случайное присвоение другого экземпляра.

final AtomicBoolean atomicFoo = new AtomicBoolean ( true ) ;

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

Лично я предпочитаю занятия Atomic…. Использование этих классов означает, что программист должен вызывать методы, а не просто выполнять назначения. Это явление является постоянным напоминанием программисту о том, что он работает в многопоточной ситуации.

Что касается существующего кода, то компилятор окажет огромную помощь при рефакторинге для использования AtomicBoolean. Каждое место, где был осуществлен доступ или манипулирование примитивом, будет выделено как ошибка компилятора, требующая вашего внимания.

Другие вопросы по теме