К
Канал Андрея про бекенд
@andrey_threads1.7K подп.
3.4Kпросмотров
18 августа 2025 г.
Score: 3.7K
Ждать вечно не лучший выбор ☠️ Помните задачку про перевод денег с одного аккаунта на другой? Одно из проблемных мест там - возможность взаимной блокировки (deadlock), когда первый поток выполняет перевод с аккаунта с id = 1 на аккаунт с id = 2, а второй поток переводит наоборот со второго на первый аккаунт. Соответственно, может возникнуть ситуация захвата ресурса “крест-накрест”. Один поток захватил блокировку на аккаунт 1 и ждет аккаунта 2, второй поток захватил второй аккаунт и ждет первого. 📌 На собеседовании могут спросить, как разрешить данную ситуацию. Каноничным ответом будет: “использовать иерархическую блокировку”. Суть подхода заключается в том, чтобы всегда захватывать и освобождать блокировки в одинаковом порядке. В данном случае, мы могли бы всегда сначала захватывать блокировку для аккаунта с меньшим ID, потом с большим. Это гарантирует отсутствие взаимной блокировки. Можете почитать про эту технику в интернете. Знать про иерархическую блокировку, конечно, стоит. Однако на практике я не видел ее использование в промышленном (не библиотечном) коде. ⏲ Есть более простая техника, которая по моему мнению должна применяться разработчиками гораздо чаще. Суть техники - не блокировать поток навечно в ожидании мьютекса. Большинство примитивов синхронизации включают в свой API методы, которые ограничивают максимальное время ожидания. Пример 1: интерфейс java.util.concurrent.locks.Lock. Метод tryLock позволяет ограничивать максимальное время, за которое должна быть получена блокировка. Если этого не происходит, то метод возвращает false и поток может продолжать свое выполнение. boolean tryLock(long timeout, TimeUnit unit) Аналогичный метод выставляет и java.util.concurrent.Semaphore. Пример 2: интерфейс java.util.concurrent.BlockingQueue. Методы offer и poll позволяют ограничить максимальное время ожидания при помещении и изъятии элемента из очереди соответственно. boolean offer(E e, long timeout, TimeUnit unit) boolean poll(long timeout, TimeUnit unit) ✅ Само по себе использование блокировок с ограниченным временем ожидания уже поможет вам избежать deadlock. И все, что для этого придется сделать - внести минимальное изменение в код, добавив желаемый таймаут. ❓ Может возникнуть логичный вопрос: “Но мне ведь нужен лок, а тут метод вернет false и что дальше?”. Если вам нужен лок, то вы можете пытаться захватить его в цикле (spin lock), делая несколько попыток. Таймаут даст вам возможность подсветить неудачные попытки захвата лока (логировать, писать метрики, сколько в среднем времени проходит до его успешного захвата). Иногда проблема заключается не в deadlock, а в банальном скоплении очереди на использование лока. ⚡️ Если проблема будет подсвечена, вы сможете перейти к ее решению более дорогостоящими, но и более эффективными методами. Например, реализовывать иерархическую блокировку. 🐕 Мой совет: поток - не Хатико, он не должен ждать вечно. Всегда используйте возможность ограничения максимального времени ожидания при использовании блокирующих 🔥 вызовов. #java #kotlin #threads
3.4K
просмотров
3050
символов
Нет
эмодзи
Нет
медиа

Другие посты @andrey_threads

Все посты канала →
Ждать вечно не лучший выбор ☠️ Помните задачку про перевод д — @andrey_threads | PostSniper