Как выделить потоку ресурс
Что проверяют
Вопрос сформулирован размыто, и это часть проверки: уточните ли вы, о каком ресурсе речь. Обычно имеют в виду одно из двух: дать каждому потоку свой экземпляр объекта или честно поделить ограниченный общий ресурс. Следом часто спрашивают про утечки ThreadLocal в пуле потоков.
Как отвечать
Разложите ответ по сценариям:
- свой экземпляр на поток:
ThreadLocal.withInitial(...)хранит отдельное значение для каждого потока. Классический пример: непотокобезопасныйSimpleDateFormatили контекст запроса. Так же Spring привязывает транзакцию и соединение к текущему потоку; - ограниченный общий ресурс: пул соединений (HikariCP) или
Semaphoreс N разрешениями. Поток берёт разрешение черезacquire()и отдаёт черезrelease()вfinally; - передача ресурса в задачу: объект создаётся внутри задачи или передаётся ей явно и наружу не утекает. Это самый простой способ обойтись без синхронизации;
- процессорное время:
setPriority()лишь подсказка планировщику ОС, гарантий она не даёт.
Отдельно скажите про виртуальные потоки из Java 21. Их не складывают в пул, а число одновременных обращений к ресурсу ограничивают тем же Semaphore. ThreadLocal на миллионе виртуальных потоков дорог по памяти, для передачи неизменяемого контекста есть ScopedValue, который в Java 25 вышел из preview.
Освобождение ресурса описывайте явно: try-with-resources для всего, что реализует AutoCloseable, и executor.shutdown() с awaitTermination() для пула.
Где спотыкаются
Забывают вызвать ThreadLocal.remove() в пуле потоков. Поток переиспользуется, и следующая задача видит чужие данные, а в сервлет-контейнере значение ещё и удерживает загрузчик классов после редеплоя.
Путают выделение ресурса с его защитой и отвечают про synchronized. Блокировка упорядочивает доступ к общему объекту, но потоку ничего своего не даёт.
Ставят release() вне finally или берут разрешение без таймаута. Одно исключение, и семафор навсегда теряет разрешение, а потоки выстраиваются в очередь, из которой не выйдут.