Безопасен ли вызов start() для объекта этого класса? Пример из Java Concurrency на практике

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

В листинге 5.15 http://jcip.net/listings/CellularAutomata.java из JCIP я представляю, что в каком-то основном методе можно создать объект CellularAutomata, а затем вызвать start() для этого объекта.

Однако можно ли это сделать? Когда вызывается метод запуска объекта, он создает N(число процессоров) потоков с экземплярами Worker. Однако кажется, что N потоков, созданных с рабочим объектом, могут видеть неполную ссылку или объект этого рабочего.

Причина этого заключается в том, что эта ссылка избегает во время создания объекта CellularAutomata при вызове new Runnable() и нового Worker(mainBoard.getSubBoard(count, i))

А так как рабочий [] рабочий; и CyclicBarrier барьер; являются полями объекта CellularAutomata, потоки, созданные в методе start() этого объекта, могут не видеть эти объекты в надлежащем состоянии.

Я думаю, что это похоже на пример Holder http://jcip.net/listings/StuffIntoPublic.java http://jcip.net/listings/Holder.java где поле Holder может быть невидимым для других потоков. Я понимаю, что пример Holder был проблематичным, потому что поле не было окончательным, и, следовательно, может быть невидимым, а в CellularAutomata они являются окончательными. Я читал, что класс только с окончательными полями гарантированно видимость их полей при публикации. Тем не менее, я также читал, что, хотя конечные поля могут быть единственными полями класса, если класс не сконструирован должным образом, эта гарантия утрачена. И в этом примере, так как ссылка this избегает, я предполагаю, что она построена неправильно. Вот пример неявного пропуска ссылки this, что похоже на то, что происходит в CellularAutomata. http://jcip.net/listings/ThisEscape.java

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

Спасибо

2 ответа

Решение

Вы можете прочитать соответствующий раздел Спецификация языка Java: 17.5. окончательная семантика поля

Первый соответствующий раздел (выделено мной):

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

this Ссылки не видны ни одному другому потоку до завершения работы конструктора, так что все в порядке. В этом нет ничего волшебного this ссылка "выходящая" из конструктора; Дело в том, что никакой другой поток не должен его видеть (до завершения конструктора).

Следующий абзац в JLS расширяется на этом (выделение и курсив добавлены мной):

Модель использования для конечных полей проста: установите конечные поля для объекта в конструкторе этого объекта; и не пишите ссылку на объект, который создается в месте, где другой поток может увидеть его до завершения конструктора объекта. Если это следует, то, когда объект виден другим потоком, этот поток всегда будет видеть правильно построенную версию конечных полей этого объекта.

Опасность в разрешении this побег - это то, что его можно увидеть до того, как он будет полностью построен. В этом случае это не проблема, потому что исполняемый файл не выполняется до start() вызывается, что должно быть после завершения конструктора.

Кроме того, помимо final В полевых гарантиях между назначением mainBoard и выполнение работоспособного. Одним из них является призыв к Thread.start() тем, что будет последним потоком, входящим в барьер, что происходит - перед любым действием в запущенном потоке. Тогда есть фактический вызов CylicBarrier.await(), которые происходят перед действиями, которые являются частью барьерного действия.

Так что я бы сказал, что код довольно безопасный.

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