Вопрос с собеседования · Java

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

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

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

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

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

Подробно

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

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования