Многопоточность Java и безопасная публикация

После прочтения " Java одновременно на практике" и " OSGI на практике" я нашел конкретную тему очень интересной; Безопасная публикация. Следующее от JCIP:

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

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

Мой первый вопрос: сколько разработчиков Java знают об этом (проблема)? Сколько реальных приложений Java действительно следуют этому, И действительно ли это настоящая проблема? У меня есть ощущение, что 99% реализованных JVM не являются "злом", т. Е. Потоку не гарантируется (на самом деле его практическое (почти) "невозможно") видеть устаревшие данные только потому, что ссылка не следует за "Безопасная публикация идиома" выше.

6 ответов

Решение

Пропорционально, вероятно, справедливо будет сказать, что очень немногие программисты в достаточной степени понимают синхронизацию и параллелизм. Кто знает, сколько сейчас существует серверных приложений, управляющих финансовыми транзакциями, медицинскими записями, полицейскими записями, телефонией и т. Д., Которые полны ошибок синхронизации и, по сути, работают случайно или очень редко из-за сбоя (никогда не слышали, чтобы кто-то получил фантом телефонный звонок добавлен к их счету за телефон?) по причинам, которые никогда не рассматривались и не доходили до сути.

Публикация объектов представляет собой особую проблему, потому что ее часто упускают из виду, и для компиляторов вполне разумно делать оптимизацию, которая может привести к неожиданному поведению, если вы не знаете об этом: в JIT-скомпилированном коде, сохраняя указатель, затем его увеличение и сохранение данных - очень разумная вещь. Вы можете подумать, что это "зло", но на низком уровне это действительно то, чего вы ожидаете от спецификации JVM. (Между прочим, я слышал о реальных программах, работающих в JRockit, страдающих от этой проблемы - это не чисто теоретическое.)

Если вы знаете, что в вашем приложении есть ошибки синхронизации, но в текущей JVM на вашем текущем оборудовании нет сбоев, тогда (a) поздравляем; и (b) сейчас самое время "спокойно идти к пожарному выходу", исправлять свой код и обучать своих программистов, прежде чем вам нужно будет обновить слишком много компонентов.

"Это действительно настоящая проблема?"

Да, конечно. Даже самое тривиальное веб-приложение сталкивается с проблемами, связанными с параллелизмом. К сервлетам обращаются, например, из нескольких потоков.

Другая проблема заключается в том, что многопоточность и параллелизм очень трудно правильно обрабатывать. Это почти слишком сложно. Вот почему мы наблюдаем появление таких тенденций, как транзакционная память, и таких языков, как Clojure, которые, как мы надеемся, облегчают параллелизм. Но у нас есть пути, прежде чем они станут основным потоком. Таким образом, мы должны делать все возможное с тем, что имеем. Чтение JCiP - очень хорошее начало.

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

Во-первых, "безопасная публикация" не совсем идиома (ИМО). Это исходит прямо из языка.

Были случаи проблем с небезопасной публикацией, например, с использованием NIO.

Большая часть кода Java написана очень плохо. Потоковый код, очевидно, сложнее, чем обычный бизнес-код.

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

Особенно с веб-приложениями, вы часто можете сойти с рук или, по крайней мере, сойти с рук. Если у вас есть экземпляры на основе Spring, управляющие созданием объектов и сервлетами без сохранения состояния, вы часто можете притворяться, что такой вещи, как синхронизация, не существует, и именно в этом случае заканчивается множество приложений. В конце концов кто-то начинает помещать какое-то общее состояние туда, где оно не принадлежит, и через 3 месяца кто-то замечает некоторые странные периодические ошибки. Это часто "достаточно хорошо" для многих людей (если вы не пишете банковские транзакции) .

Сколько разработчиков Java знают об этой проблеме? Трудно сказать, так как это сильно зависит от того, где вы работаете.

Я бы сказал, что очень немногие программисты уходят от этой проблемы. Когда вы видели последний пример кода, в котором использовалось ключевое слово volatile? Тем не менее, большинство других условных упомянуто - я просто воспринимал как должное как лучшие практики.

Если разработчик полностью пренебрегает этими условиями, они быстро столкнутся с многопоточными ошибками.

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