Java не-финальные int (s) видимые после конструкции - PullRequest
5 голосов
/ 14 марта 2011

У меня есть класс Java с неконечной переменной int, которую я явно инициализировал в конструкторе равным 0. Все остальные способы доступа к переменной управляются с помощью ReentrantLock.Должен ли я волноваться, что потоки не увидят начальное значение 0, потому что я не использовал блокировку в конструкторе?

Ответы [ 2 ]

9 голосов
/ 14 марта 2011

Да, ты должен волноваться.Во избежание проблем в этом случае вам необходима безопасная публикация ссылки на объект.

С Параллельный интерфейс Java на практике :

Для безопасной публикации объекта обассылка на объект и состояние объекта должны быть видны другим потокам одновременно.Правильно сконструированный объект можно безопасно опубликовать:

  • Инициализация ссылки на объект из статического инициализатора;
  • Сохранение ссылки на него в энергозависимом поле или AtomicReference;
  • Сохранение ссылки на него в конечном поле правильно построенного объекта;или
  • Сохранение ссылки на него в поле, которое должным образом защищено замком.

В других случаях вы можете (теоретически) столкнуться с ситуацией, когда результат new будет доступно другим потокам до завершения вызова конструктора (из-за возможного переупорядочения операции).

Обратите внимание, однако, что если 0 является значением по умолчанию, а не значением, записанным в конструкторе, этогарантированно видимый ( JLS §17.4.4 ):

  • Запись значения по умолчанию (ноль, ложь или ноль) для каждой переменной синхронизируется спервое действие в каждой теме.Хотя может показаться немного странным записать значение по умолчанию в переменную до того, как объект, содержащий переменную, будет выделен, концептуально каждый объект создается в начале программы с его инициализированными значениями по умолчанию
2 голосов
/ 14 марта 2011

Из Java-параллелизма на практике:

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

Объект не публикуется безопасно, просто не публикуя его ссылку в конструкторе. То есть конструктор не обеспечивает необходимые отношения «происходит до». Таким образом, даже если вы не публикуете ссылку на объект в его конструкторе, у вас могут возникнуть проблемы с параллелизмом. Подробности и примеры см. В соответствующей главе в книге.

Чтобы сделать безопасную публикацию, авторы предлагают следующие способы:

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

Инициализация ссылки на объект из статический инициализатор;

Сохранение ссылки на него в изменчивое поле или AtomicReference;

Сохранение ссылки на него в финале поле правильно построено объект; или

Сохранение ссылки на него в поле это правильно охраняется замком. В сущности, между конструкцией объекта и доступом к этому объекту другим потоком должна быть установлена ​​правильная связь «происходит раньше».

Как отмечают авторы, объекты, которые передаются через безопасные коллекции потоков, также безопасно публикуются (например, элемент, переданный через рабочий поток через LinkedBlockingQueue и т. Д.).

Это правда, что сохранение значения в примитивных int полях (но не в 64-битных полях, таких как long) является атомарным, что означает, что вы не можете наблюдать «странное» значение, даже если вы обращаетесь к этому полю в не потокобезопасный способ из другого потока. Но когда объект еще не построен должным образом, могут произойти другие плохие вещи (честно говоря, я не знаю, что именно может произойти, но это, безусловно, не стоит пытаться).

Подводя итог, вам необходимо в любом случае безопасно опубликовать объект, после чего значение будет правильно установлено на 0, а объект будет создан правильно.

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