Получить доступ

Что даёт переменная типа ThreadLocal?

JuniorМногопоточность
Ещё спрашивают так:
  • Где используют ThreadLocal?
  • Почему ThreadLocal опасен в пуле потоков?
Коротко

ThreadLocal — своя ячейка значения для каждого потока: синхронизация не нужна, потому что значение никто не разделяет.

  • Применение: контекст запроса, пользователь, транзакция, непотокобезопасный форматтер
  • В пуле потоки переиспользуются: не очищенное значение достанется следующему запросу и утечёт память

А ещё Всегда remove() в finally; для виртуальных потоков есть ScopedValue

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

ThreadLocal<T> хранит отдельное значение для каждого потока: set() и get() работают с ячейкой текущего потока, другие потоки её не видят. Раз значение не разделяется, синхронизация не нужна.

Где используют:

  • контекст обработки запроса — id запроса для логов, текущий пользователь (так устроены SecurityContextHolder в Spring Security и MDC в логировании);
  • привязка транзакции или соединения к потоку;
  • непотокобезопасные объекты, которые дорого создавать, — например, старый SimpleDateFormat.

Главная опасность — пулы потоков. Поток в пуле живёт долго и обслуживает много задач. Если не очистить значение, следующая задача увидит чужой контекст (данные другого пользователя!), а объекты не будут собраны сборщиком — утечка памяти. Поэтому шаблон: set в начале обработки, remove() в finally.

С виртуальными потоками (Java 21) их могут быть миллионы, и ThreadLocal становится дорогим по памяти; для передачи контекста появился ScopedValue.

Пример

private static final ThreadLocal<String> REQUEST_ID = new ThreadLocal<>();

void handle(Request req) {
    REQUEST_ID.set(req.id());
    try {
        process(req);
    } finally {
        REQUEST_ID.remove();   // обязательно в пуле потоков
    }
}

Что хотят услышать

  • Отдельное значение на поток, без синхронизации.
  • Примеры применения.
  • Проблема пулов: утечки и чужой контекст, remove в finally.

Частые ошибки

  • Не очищать значение после обработки в пуле потоков.
  • Рассчитывать, что значение перейдёт в порождённые задачи.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓Отдельное значение для каждого потока: потоки не видят значений друг друга
  • ✗Общее значение, синхронизированное между всеми потоками
  • ✗Копию переменной, обновляемую при каждом переключении контекста
  • ✗Значение, доступное только главному потоку

Что спросят дальше

  • Почему это опасно при работе с пулом потоков?
  • Что происходит с таким значением при переходе в другой поток?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем