Введение в ThreadLocal на Java
Краткое и практическое руководство по использованию ThreadLocal для хранения данных, специфичных для потоков, в Java.
1. Обзор
2. ThreadLocal API
Конструкция Threadlocal позволяет нам хранить данные, которые будут доступны только конкретному потоку .
3. Хранение пользовательских данных на карте
Давайте рассмотрим программу, которая должна хранить пользовательские Контекстные данные для каждого заданного идентификатора пользователя:
Затем мы сохраняем этот контекст в Concurrenthashmap с ключом userId :
Мы можем легко протестировать ваш код, создав и запустив два потока для двух разных идентификаторов пользователей и утверждая, что у нас есть две записи в userContextPerUserId map:
4. Хранение пользовательских данных в ThreadLocal
Метод run() извлекает пользовательский контекст и сохраняет его в переменной ThreadLocal с помощью метода set() :
Мы можем проверить это, запустив два потока, которые будут выполнять действие для данного userId :
После запуска этого кода мы увидим на стандартном выходе, что ThreadLocal был установлен для данного потока:
5. ThreadLocals и пулы потоков
ThreadLocal предоставляет простой в использовании API для ограничения некоторых значений для каждого потока. Это разумный способ достижения потокобезопасности в Java. Однако мы должны быть особенно осторожны, когда мы используем ThreadLocal s и пулы потоков вместе.
Чтобы лучше понять возможную оговорку, давайте рассмотрим следующий сценарий:
Это может привести к неожиданным последствиям в сильно параллельных приложениях.
5.1. Расширение ThreadPoolExecutor
Как оказалось, можно расширить класс ThreadPoolExecutor и предоставить пользовательскую реализацию крючка для методов beforeExecute() и afterExecute () . Пул потоков вызовет метод beforeExecute() перед запуском чего-либо с использованием заимствованного потока. С другой стороны, он вызовет метод afterExecute() после выполнения нашей логики.
Поэтому мы можем расширить класс ThreadPoolExecutor и удалить данные ThreadLocal в методе afterExecute() :
6. Заключение
Русские Блоги
Подробное объяснение ThreadLocal в Java
Подробное объяснение ThreadLocal в Java
1. Введение в ThreadLocal
ThreadLocal предоставляется пакетом JDK. Он предоставляет локальные переменные потока. Если вы создаете переменную ThreadLocal, каждый поток, который обращается к этой переменной, будет иметь копию этой переменной. В фактической многопоточной операции операция является его собственной локальной памятью. Переменные в, что позволяет избежать проблем с безопасностью потоков, как показано на следующем рисунке.
Во-вторых, ThreadLocal прост в использовании
В следующем примере запускаются два потока, значение локальной переменной устанавливается в каждом потоке, а затем вызывается метод печати для печати значения текущей локальной переменной. Если вы вызовете метод удаления локальной переменной после печати, переменная в локальной памяти будет удалена, код выглядит следующим образом
Вот результат после бега:
В-третьих, принцип реализации ThreadLocal
Ниже представлена структура диаграммы классов ThreadLocal, как видно из рисунка: В классе Thread есть две переменные threadLocals и inheritableThreadLocals, обе из которых являются переменными типа ThreadLocalMap во внутреннем классе ThreadLocal. Мы можем обнаружить, что она фактически похожа на одну, посмотрев на внутреннюю ThreadLocalMap. HashMap. По умолчанию эти две переменные в каждом потоке равны нулю.
1, установить исходный код метода
В приведенном выше коде (2) вызовите метод getMap, чтобы получить threadLocals, соответствующий текущему потоку (см. Приведенную выше иллюстрацию и текстовое описание), код метода выглядит следующим образом
Метод createMap не только создает threadLocals, но также добавляет значение локальных переменных, которые будут добавлены в threadLocals.
2, получить исходный код метода
В реализации метода get сначала получите текущий вызывающий поток, если threadLocals текущего потока не равен нулю, напрямую верните значение локальной переменной, привязанной к текущему потоку, в противном случае выполните метод setInitialValue для инициализации переменной threadLocals. В методе setInitialValue, аналогично реализации метода set, он предназначен для определения того, имеет ли значение переменной threadLocals текущего потока значение null. Если это так, добавьте локальную переменную (на этот раз инициализируется, поэтому добавленное значение равно null), в противном случае создается переменная threadLocals, то же Добавленная стоимость равна нулю.
3, реализация метода удаления
Метод remove определяет, является ли переменная threadLocals, соответствующая текущему потоку, нулевой, и, если она не равна нулю, напрямую удаляет переменную threadLocals, указанную в текущем потоке.
В-четвертых, ThreadLocal не поддерживает наследование.
Пять, класс InheritableThreadLocal
Упомянутый выше класс ThreadLocal не может предоставлять дочерним потокам доступ к локальным переменным родительского потока, в то время как класс InheritableThreadLocal может это делать. Исходный код этого класса выглядит следующим образом
Как видно из приведенного выше кода, класс InheritableThreadLocal наследует класс ThreadLocal и переписывает три метода childValue, getMap и createMap. Когда вызывается метод createMap (метод должен вызываться, когда карта, полученная, когда текущий поток вызывает метод set, имеет значение null), он создает наследуемыйThreadLocal вместо threadLocals. Таким же образом метод getMap возвращает не threadLocals, а inheritableThreadLocal, когда текущий вызывающий поток вызывает метод get.
Давайте посмотрим, когда будет выполнен переписанный метод childValue и как разрешить дочернему потоку получить доступ к значению локальной переменной родительского потока. Начнем с класса Thread
В методе инициализации сначала (1) получает текущий поток (родительский поток), а затем (2) оценивает, имеет ли свойство inheritableThreadLocals текущего родительского потока значение null, а затем вызывает createInheritedMap для создания нового с наследуемымиThreadLocals родительского потока в качестве параметра конструктора. Затем дочернему потоку присваивается переменная ThreadLocalMap. Ниже приведены метод createInheritedMap и метод построения ThreadLocalMap.
В конструкторе присвойте значение переменной-члену inheritableThreadLocals родительского потока новому объекту ThreadLocalMap. НаследуемыеThreadLocals назначаются дочернему потоку после возврата. Короче говоря, класс InheritableThreadLocals сохраняет локальные переменные в переменной inheritableThreadLocals определенного потока, переопределяя методы getMap и createMap. Когда поток устанавливает переменную с помощью метода set или get экземпляра InheritableThreadLocals, он создает переменную inheritableThreadLocals текущего потока. Когда родительский поток создает дочерний поток, конструктор в ThreadLocalMap копирует переменные из наследуемогоThreadLocals родительского потока в переменную inheritableThreadLocals дочернего потока.
В-шестых, из ThreadLocalMap, чтобы увидеть проблему утечки памяти из-за неправильного использования ThreadLocal
1. Основные концепции
①Сильная ссылка: тип ссылки по умолчанию в Java. Если объект имеет сильную ссылку, он не будет GC, пока ссылка все еще существует.
②Программная ссылка: Короче говоря, если объект имеет слабую ссылку, объект не будет GC до появления OOM в JVM (то есть, если память будет использована в достаточной степени); объект будет GC только когда памяти JVM недостаточно. Мягкая ссылка используется вместе с очередью ссылок. Если объект, на который ссылается мягкая ссылка, переработан, ссылка будет добавлена в связанную с ним очередь ссылок.
2. Проанализируйте внутреннюю реализацию ThreadLocalMap.
Выше мы знаем, что ThreadLocalMap на самом деле является массивом Entry
Учтите, что эта переменная ThreadLocal не имеет других сильных зависимостей. Если текущий поток все еще существует, потому что ключ в ThreadLocalMap потока является слабой ссылкой, слабая ссылка на переменную ThreadLocal в ThreadLocalMap текущего потока будет повторно использована во время gc, но соответствующее значение Он все еще существует, что может вызвать утечку памяти (потому что в это время ThreadLocalMap будет иметь элементы записи, ключ которых равен нулю, но значение не равно нулю).
Сводка: ключ Entry в THreadLocalMap использует слабую ссылку на объект ThreadLocal. Если нет другого места, где можно было бы полагаться на ThreadLoca, объект ThreadLocal в ThreadLocalMap будет переработан, но соответствующий не будет переработан. Это возможно на карте. Есть элементы, в которых ключ равен нулю, но значение не равно нулю. Это требует, чтобы метод удаления был вызван вовремя после использования, чтобы избежать утечки памяти.
Солянка
За последнее время скопилось несколько различных мыслей. Надеюсь, какие-то из них покажутся интересными.
Итак, в солянке:
1. Java: что такое ThreadLocal и InheritableThreadLocal
2. Palm Pre: личные впечатления
3. Android: как развернуть сервер на телефоне
4. Интерфейсы: концепция страницы «про нас»
5. Книжки: впечатления от Pragmatic Thinking and Learning: Refactor Your Wetware
1. Java: что такое ThreadLocal и InheritableThreadLocal
2. Palm Pre: личные впечатления

Говорят, что все в Palm очень гордятся продуктом. С моей точки зрения, есть чем гордится.
3. Android: как развернуть сервер на телефоне
while ( isRunning )
<
// Ждём нового клиента
final Socket socket = serverSocket.accept();
Пожалуй, стоит лишь предупредить разработчиков об аккуротном закрытие сокетов, Socket::isClosed() не всегда адекватно выражает состояние соединения.
4. Интерфейсы: концепция страницы «про нас»
Вот такая идея: на странице «про нас» поместить общую фотографию всех разработчиков. Обводишь мышкой лицо разработчика, а слева появляется информация о том, чем человек занимался. Ну и, может, форма отправки сообщения. Что-то такое:
5. Книжки: впечатления от Pragmatic Thinking and Learning: Refactor Your Wetware
Основная идея книжки: те, кто занимается умственным трудом должны развивать не только «software» мозга, но и «hardware» («wetware», в случае человеков). Постоянно учиться, менять сферы деятельности, запоминать новую информацию, не лениться быть любопытным. Эти активности помогут мозгу не прекращать создавать новые нейронные связи и менять существующие.
Более того, автор продвигает интересный тезис: развите мозга может не прекращаться в определённом возрасте. То есть, при желании, с возрастом можно не растерять остроту мышления и способность учиться новому. Напротив, можно развить мозг так, что он будет эффективно усваивть и обрабатывать информацию.
Очень рекомендую: Pragmatic Thinking and Learning: Refactor Your Wetware.
Надеюсь, в моей солянке оказалось достаточно копчёностей, и читатель получил от неё удовольствие.
Параллелизм Java — класс ThreadLocal
Класс ThreadLocal используется для создания локальных переменных потока, которые могут быть прочитаны и записаны только одним потоком. Например, если два потока обращаются к коду, имеющему ссылку на одну и ту же переменную threadLocal, то каждый поток не увидит никаких изменений в переменной threadLocal, выполненных другим потоком.
ThreadLocal Методы
Ниже приведен список важных методов, доступных в классе ThreadLocal.
| Sr.No. | Метод и описание |
|---|---|
| 1 |





