Вопрос-ответ

When and how should I use a ThreadLocal variable?

Когда и как я должен использовать локальную переменную ThreadLocal?

Когда я должен использовать ThreadLocal переменную?

Как она используется?

Переведено автоматически
Ответ 1

Одно из возможных (и распространенных) применений - это когда у вас есть какой-то объект, который не является потокобезопасным, но вы хотите избежать синхронизации доступа к этому объекту (я смотрю на вас, SimpleDateFormat). Вместо этого предоставьте каждому потоку свой собственный экземпляр объекта.

Например:

public class Foo
{
// SimpleDateFormat is not thread-safe, so give one to each thread
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};

public String formatIt(Date date)
{
return formatter.get().format(date);
}
}

Документация.

Ответ 2

Поскольку a ThreadLocal является ссылкой на данные внутри данного Thread, вы можете столкнуться с утечками загрузки классов при использовании ThreadLocals на серверах приложений, использующих пулы потоков. Вам нужно быть очень осторожным при очистке любых ThreadLocalданных, которые вы get()используете set() или ThreadLocal с помощью метода remove()'s'.

Если вы не очистите ее, когда закончите, все содержащиеся в ней ссылки на классы, загруженные как часть развернутого веб-приложения, останутся в постоянной куче и мусор никогда не будет собран. Повторное развертывание / отмена развертывания веб-приложения не приведет к очистке каждой Thread ссылки на классы вашего веб-приложения, поскольку Thread это не то, что принадлежит вашему веб-приложению. Каждое последующее развертывание будет создавать новый экземпляр класса, который никогда не будет собираться мусором.

В конечном итоге вы столкнетесь с исключениями нехватки памяти из-за java.lang.OutOfMemoryError: PermGen space и после некоторого поиска в Google, вероятно, их количество просто увеличится -XX:MaxPermSize вместо исправления ошибки.

Если вы в конечном итоге столкнетесь с этими проблемами, вы можете определить, какой поток и класс сохраняет эти ссылки, используя анализатор памяти Eclipse и / или следуя руководству Фрэнка Киевьета и последующим инструкциям.

Обновление: Заново обнаружил запись в блоге Алекса Вассера, которая помогла мне отследить некоторые ThreadLocal проблемы, с которыми я столкнулся.

Ответ 3

Многие фреймворки используют ThreadLocals для поддержания некоторого контекста, связанного с текущим потоком. Например, когда текущая транзакция хранится в ThreadLocal , вам не нужно передавать ее в качестве параметра при каждом вызове метода, на случай, если кому-то в стеке потребуется доступ к ней. Веб-приложения могут хранить информацию о текущем запросе и сеансе в ThreadLocal, чтобы приложение имело к ним легкий доступ. С помощью Guice вы можете использовать ThreadLocals при реализации пользовательских областей для вводимых объектов (в областях сервлета Guice по умолчанию, скорее всего, они также используются).

ThreadLocals - это один из видов глобальных переменных (хотя и немного меньшее зло, поскольку они ограничены одним потоком), поэтому вам следует быть осторожным при их использовании, чтобы избежать нежелательных побочных эффектов и утечек памяти. Разработайте свои API таким образом, чтобы значения ThreadLocal всегда автоматически удалялись, когда они больше не нужны, и чтобы неправильное использование API было невозможно (например, как это). ThreadLocals можно использовать для очистки кода, а в некоторых редких случаях это единственный способ заставить что-то работать (в моем текущем проекте было два таких случая; они задокументированы здесь в разделе "Статические поля и глобальные переменные").

Ответ 4

В Java, если у вас есть данные, которые могут варьироваться в зависимости от потока, ваш выбор - передать эти данные каждому методу, который в них нуждается (или может понадобиться), или связать данные с потоком. Передача данных повсюду может быть работоспособной, если всем вашим методам уже необходимо передавать общую переменную "контекста".

Если это не так, возможно, вы не захотите загромождать сигнатуры вашего метода дополнительным параметром. В мире без потоков вы могли бы решить проблему с помощью Java-эквивалента глобальной переменной. В многопоточном word эквивалентом глобальной переменной является локальная переменная потока.

java multithreading concurrency