Java Development
Александр Вотин, Backend developer · 05.11
Многопоточные коллекции в Java. Как не угробить данные
Итак, представь ситуацию, у тебя в приложении несколько потоков (то есть задач), и каждый из них хочет одновременно читать и изменять одни и те же данные. Если использовать обычные коллекции вроде ArrayList или HashMap, начнутся ошибки, потому что Java не умеет их правильно обрабатывать, когда доступ идёт из нескольких потоков. Для этого и нужны многопоточные коллекции.
ConcurrentHashMap — потокобезопасный аналог HashMap. Позволяет разным потокам одновременно читать и писать в карту, не создавая конфликтов. CopyOnWriteArrayList — потокобезопасная версия ArrayList, которая при каждом изменении создаёт копию списка. Удобна, если ты в основном читаешь данные, а записываешь редко. BlockingQueue — особая очередь, где добавление и получение элементов блокируется, пока не будет выполнено условие. Полезно, например, для очереди задач, когда один поток добавляет, а другой — забирает.
Допустим, у тебя есть чат, и каждому пользователю нужно сохранять статус ("Онлайн", "Оффлайн", "Не беспокоить" и т.д.). Поскольку пользователей много, их статусы постоянно меняются и обновляются в реальном времени. Тут нам и поможет ConcurrentHashMap.
В отличие от обычного HashMap, ConcurrentHashMap позволяет разным потокам одновременно работать с разными частями карты. Он разбивает карту на сегменты и блокирует не всю карту, а только ту часть, с которой в данный момент работает конкретный поток. Это помогает быстрее обрабатывать запросы от нескольких потоков сразу.
Давай напишем класс Chat, где для каждого пользователя будет храниться его статус в ConcurrentHashMap.
- String — имя пользователя (ключ), String — его статус (значение).
- put добавляет новый статус, если такого пользователя ещё нет, или обновляет, если пользователь уже существует. Всё это потокобезопасно, поэтому если несколько потоков попытаются одновременно обновить статус, программа не "слетит".
- statuses.getOrDefault(user, "Неизвестно"). Этот метод возвращает статус пользователя, если он есть в карте, или "Неизвестно", если такого пользователя нет. getOrDefault полезен, чтобы не ловить null, если статус ещё не задан.
- statuses.remove(user). Когда пользователь выходит, мы можем безопасно удалить его статус из карты. Здесь remove тоже потокобезопасен.
Важно помнить ConcurrentHashMap удобен, но у него есть ограничения, операции, которые требуют полного перебора карты (например, подсчёт всех записей), могут выполняться медленно, так как при этом карта может заблокироваться целиком.
Используй ConcurrentHashMap, если тебе нужно безопасно хранить и изменять данные в многопоточной среде, например, для таких задач, как хранение сессий, статусов или любых других быстрых обновлений от разных потоков.
еще контент автора
еще контент автора
Java Development
Александр Вотин, Backend developer · 05.11
войдите, чтобы увидеть
и подписаться на интересных профи