Вопрос звучит просто: «зачем нужен ThreadLocal и чем он опасен в проде». Кандидаты обычно отвечают про хранение контекста пользователя между слоями без протаскивания параметра через весь стек вызовов — это правда, но только половина ответа.

Вторая половина — про то, что происходит, когда поток возвращается в пул. Tomcat и любой другой сервер держит фиксированный пул потоков и переиспользует их между запросами. Если вы положили что-то в ThreadLocal в начале обработки запроса и не убрали в конце, следующий запрос, которому достанется тот же поток, получит чужие данные.

public class RequestContextHolder { private static final ThreadLocal CONTEXT = new ThreadLocal<>();

public static void set(UserContext ctx) { CONTEXT.set(ctx); }

public static UserContext get() { return CONTEXT.get(); }

public static void clear() { CONTEXT.remove(); } }

Если clear() не вызван в finally фильтра или интерцептора, а исключение прервало обработку до штатной очистки — следующий запрос на этом потоке стартует с чужим UserContext внутри.

Уточняющий вопрос на этом месте — как обнаружить такую утечку в проде, если тесты не ловят её на одном потоке. Обычно это всплывает как редкие, трудно воспроизводимые баги под нагрузкой: один пользователь внезапно видит данные другого. Диагностируют логированием thread-id вместе с user-id на входе и выходе фильтра и поиском аномалий, где id пользователя меняется без смены потока.

ThreadLocal не течёт сам по себе — течёт отсутствие finally рядом с ним.

Тренажёр: 900+ вопросов и задач, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки