Singleton - Суть: гарантирует существование ровно одного экземпляра класса и предоставляет глобальную точку доступа. - Пример (псевдокод): - жёсткая инициализация: `class Singleton { private static final INSTANCE = new Singleton(); public static getInstance() { return INSTANCE; } }` - ленивый + DCL (в Java-подобном стиле): `private static volatile instance; public static getInstance() { if (instance == null) { synchronized(lock) { if (instance == null) instance = new Singleton(); } } return instance; }` - Плюсы в многопоточности: - централизованная инициализация ресурсов (удобно для кэширования, управления конфигом). - при правильной реализации (immutable/инициализация при загрузке или enum в Java) даёт безопасную публикацию. - Минусы/риски: - неправильная ленивость (отсутствие `volatile` или неверный DCL) — race condition и частично построенные объекты. - точка глобальной блокировки/синхронизации — узкое место и снижение масштабируемости. - затрудняет тестирование (глобальное состояние) и может вести к скрытым зависимостям. - Рекомендации: - предпочесть eager init или язык-специфичные безопасные механизмы (enum в Java). - если нужно lazy+неблокирующее — использовать `AtomicReference`, holder-idiom или фабрики. Observer - Суть: субъект хранит список наблюдателей и уведомляет их при изменениях. - Пример (псевдокод): `subject.notify() { for (o : observers) o.update(event); }` - Плюсы в многопоточности: - облегчает асинхронную обработку: подписчики могут работать параллельно. - хорошо сочетается с потокобезопасными коллекциями и очередями (decoupling). - Минусы/риски: - concurrent modification: добавление/удаление наблюдателей во время уведомления может привести к исключениям или пропущенным уведомлениям. - наблюдатель может выбросить исключение или долго блокировать — замедлит/сломает рассылку. - порядок уведомлений и согласованность состояния сложно гарантировать. - возможны дедлоки, если в колбэке наблюдатель вызывает методы субъекта, требующие той же блокировки. - Рекомендации: - использовать snapshot-рассылку или CopyOnWrite коллекции для списка observers. - не держать общие блокировки во время вызовов `update` — делать асинхронную доставку через executor. - явно документировать гарантии ordering/at-least-once/at-most-once; обрабатывать исключения наблюдателей. Strategy - Суть: инкапсулирует семейство алгоритмов, делает их взаимозаменяемыми. - Пример (псевдокод): `context.setStrategy(newStrategy); result = context.executeStrategy(data);` - Плюсы в многопоточности: - если стратегии stateless/immutable — полностью потокобезопасны и легко переиспользуются. - смена алгоритма в рантайме возможна через атомарную ссылку без глобальных блокировок. - Минусы/риски: - stateful-стратегии требуют синхронизации или защиты состояния (иначе race condition). - смена стратегии во время выполнения операции может приводить к неоднородности поведения, если не контролировать видимость. - Рекомендации: - делать стратегии по возможности immutable/stateless. - при необходимости менять стратегию — хранить ссылку в `volatile`/`AtomicReference` и переключать атомарно. - если стратегия хранит mutable state, ограничить конкурентный доступ (локи, thread-local, или копирование состояния). Общие практики для многопоточных систем - Предпочитать immutable объекты и stateless-компоненты. - Минимизировать время удержания блокировок; не вызывать внешние колбэки, держа лок. - Использовать хорошо протестированные concurrent-коллекции (CopyOnWrite, ConcurrentHashMap) и атомарные примитивы. - Документировать инварианты и ожидаемую модель памяти (visibility, ordering). - При высокой нагрузке рассмотреть lock-free/многопоточную архитектуру (sharding, actor-подход, очереди). Если нужно, могу привести конкретные фрагменты кода для Java/С#, показывающие безопасные реализации.
- Суть: гарантирует существование ровно одного экземпляра класса и предоставляет глобальную точку доступа.
- Пример (псевдокод):
- жёсткая инициализация: `class Singleton { private static final INSTANCE = new Singleton(); public static getInstance() { return INSTANCE; } }`
- ленивый + DCL (в Java-подобном стиле): `private static volatile instance; public static getInstance() { if (instance == null) { synchronized(lock) { if (instance == null) instance = new Singleton(); } } return instance; }`
- Плюсы в многопоточности:
- централизованная инициализация ресурсов (удобно для кэширования, управления конфигом).
- при правильной реализации (immutable/инициализация при загрузке или enum в Java) даёт безопасную публикацию.
- Минусы/риски:
- неправильная ленивость (отсутствие `volatile` или неверный DCL) — race condition и частично построенные объекты.
- точка глобальной блокировки/синхронизации — узкое место и снижение масштабируемости.
- затрудняет тестирование (глобальное состояние) и может вести к скрытым зависимостям.
- Рекомендации:
- предпочесть eager init или язык-специфичные безопасные механизмы (enum в Java).
- если нужно lazy+неблокирующее — использовать `AtomicReference`, holder-idiom или фабрики.
Observer
- Суть: субъект хранит список наблюдателей и уведомляет их при изменениях.
- Пример (псевдокод): `subject.notify() { for (o : observers) o.update(event); }`
- Плюсы в многопоточности:
- облегчает асинхронную обработку: подписчики могут работать параллельно.
- хорошо сочетается с потокобезопасными коллекциями и очередями (decoupling).
- Минусы/риски:
- concurrent modification: добавление/удаление наблюдателей во время уведомления может привести к исключениям или пропущенным уведомлениям.
- наблюдатель может выбросить исключение или долго блокировать — замедлит/сломает рассылку.
- порядок уведомлений и согласованность состояния сложно гарантировать.
- возможны дедлоки, если в колбэке наблюдатель вызывает методы субъекта, требующие той же блокировки.
- Рекомендации:
- использовать snapshot-рассылку или CopyOnWrite коллекции для списка observers.
- не держать общие блокировки во время вызовов `update` — делать асинхронную доставку через executor.
- явно документировать гарантии ordering/at-least-once/at-most-once; обрабатывать исключения наблюдателей.
Strategy
- Суть: инкапсулирует семейство алгоритмов, делает их взаимозаменяемыми.
- Пример (псевдокод): `context.setStrategy(newStrategy); result = context.executeStrategy(data);`
- Плюсы в многопоточности:
- если стратегии stateless/immutable — полностью потокобезопасны и легко переиспользуются.
- смена алгоритма в рантайме возможна через атомарную ссылку без глобальных блокировок.
- Минусы/риски:
- stateful-стратегии требуют синхронизации или защиты состояния (иначе race condition).
- смена стратегии во время выполнения операции может приводить к неоднородности поведения, если не контролировать видимость.
- Рекомендации:
- делать стратегии по возможности immutable/stateless.
- при необходимости менять стратегию — хранить ссылку в `volatile`/`AtomicReference` и переключать атомарно.
- если стратегия хранит mutable state, ограничить конкурентный доступ (локи, thread-local, или копирование состояния).
Общие практики для многопоточных систем
- Предпочитать immutable объекты и stateless-компоненты.
- Минимизировать время удержания блокировок; не вызывать внешние колбэки, держа лок.
- Использовать хорошо протестированные concurrent-коллекции (CopyOnWrite, ConcurrentHashMap) и атомарные примитивы.
- Документировать инварианты и ожидаемую модель памяти (visibility, ordering).
- При высокой нагрузке рассмотреть lock-free/многопоточную архитектуру (sharding, actor-подход, очереди).
Если нужно, могу привести конкретные фрагменты кода для Java/С#, показывающие безопасные реализации.