безопасная публикация и преимущество неизменяемости по сравнению с эффективно неизменяемый

Я перечитываю Java Concurrency In Practice и не уверен, что полностью понимаю главу о неизменности и безопасной публикации.

В книге говорится:

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

Я не понимаю, зачем кому-то (, заинтересованному в исправлении своего кода ) небезопасно публиковать какую-либо ссылку?

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

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

И если безопасная публикация используется, чтобы убедиться, что новая ссылка видна всем потокам, то даже если объект просто фактически неизменяемый (нет полей final , но нет способ отключить их), тогда все снова в безопасности. Как говорится в книге:

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

Итак, почему неизменность (по сравнению с эффективной неизменяемостью) так важна? В каком случае потребуется небезопасная публикация?

24
задан Bruce Wayne 22 June 2015 в 17:23
поделиться

1 ответ

«Небезопасная публикация» часто подходит в тех случаях, когда желательно, чтобы другие потоки видели последнее значение, записанное в поле, но если потоки видят более раннее значение, было бы относительно безопасно. Ярким примером является кэшированное хеш-значение для String. При первом вызове hashCode() для String он вычисляет значение и кэширует его. Если другой поток, который вызывает hashCode() для той же строки, может видеть значение, вычисленное первым потоком, ему не нужно будет повторно вычислять значение хеша (таким образом, экономя время), но ничего плохого не произойдет, если второй поток не увидеть значение хеша. Это просто приведет к выполнению избыточных, но безвредных вычислений, которых можно было бы избежать. Безопасная публикация hashCode() значения хеш-функции была бы возможна, но случайные избыточные вычисления хеша намного дешевле, чем синхронизация, необходимая для безопасной публикации. Действительно, за исключением довольно длинных строк, затраты на синхронизацию, вероятно, сведут на нет любую выгоду от кэширования.

К сожалению, я не думаю, что создатели Java представляли себе ситуации, когда код записывал бы в поле и предпочитал, чтобы он был виден другим потокам, но не обращал слишком много внимания, если это не так, и где хранилась ссылка в поле, в свою очередь, идентифицирует другой объект с аналогичным полем. Это приводит к ситуациям, когда написание семантически правильного кода намного сложнее и, вероятно, медленнее, чем код, который может сработать, но семантика которого не гарантируется. Я не знаю действительно хорошего средства для этого в некоторых случаях, кроме использования некоторых необязательных final полей, чтобы гарантировать, что вещи должным образом «опубликованы».

2
ответ дан 29 November 2019 в 00:22
поделиться
Другие вопросы по тегам:

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