Исследуйте ThreadLocal

Java

учить без конец территория , а также июнь общий нежелание .

Функции

  • ThreadLocalЭто переменная внутри потока, используемая только в этом потоке и изолирующая другие потоки.
  • ThreadLocalподдерживать внутреннююThreadLocalMap
  • Threadссылается внутриThreadLocalMap
  • ThreadLocalMapможно спастипары ключ-значение, ноThreadLocalможет содержать только одно значение, и данные каждого потока не мешают друг другу
  • ThreadLocalMapна момент храненияkeyвсегда актуальноThreadLocal
  • ThreadLocalMapна момент храненияkeyдаслабая ссылкаиз

ThreadLocalMap

каждыйThreadLocalМожно сохранить только одни данные, если вам нужно сохранить несколько значений, вы можете определить несколькоThreadLocal.ThreadLocalподдерживалThreadLocalMapиспользуется для хранения этих значений.

ThreadLocalMapне достигMapинтерфейс, который определяетEntryМассив, каждыйEntryк<key,value>хранить значение в видеkeyдля текущегоThreadLocalсам,valueзначение для сохранения.

УведомлениеEntryнаследоватьWeakReference,этоkeyдаслабая ссылка, будет собираться мусор, поэтому будетkeyдляnullСлучай

ThreadLocalMapПредусмотрено три метода:

  • set(): с текущимThreadLocalдляkeyсохранить значение
  • get(): с текущимThreadLocalдляkeyПолучить сохраненное значение
  • удалить(): очистить данные

метод set()

  • получить текущий потокThread.currentThread()
  • Получить текущий потокThreadLocalMap
  • судитьThreadLocalMapон существует
  • не существует, черезcreateMap, инициализироватьThreadLocalMapи назначить
  • существует, токThreadLocalтак какkey, чтобы выполнить операцию вставки:
    • Получить позицию для вставки через хеш-значение ThreadLocal
    • Если запись в текущем местоположении пуста, инициализируйте объект Entry непосредственно в этом месте, чтобы реализовать операцию вставки;
    • Если ключ ввода текущей позиции совпадает с ключом, который нужно установить, перезапишите исходное значение.
    • Если ключ текущей позиции Entry равен нулю:
      • цикл, чтобы получить следующую позицию
      • Если ключ совпадает с установленным ключом, значение в этой позиции перезаписывается, и эта позиция обменивается в записи, которая будет вставлена ​​в точку, которая будет вставлена, и значение, ключ которого нуль очищен;
      • Если запись в текущей позиции равна нулю, выйдите из цикла, сгенерируйте новую запись в текущей позиции и очистите значение, ключ которого равен нулю;

получить () метод

  • получить текущий потокThread.currentThread()
  • Получить из текущей темыThreadLocalMap
  • судитьThreadLocalMapон существует
  • несуществующий вызовsetInitialValueинициализировать и вернутьnull;
  • существует, текущийThreadLocalтак какkeyПолучите значение:
    • Получите местоположение, чтобы получить значение через хеш-значение ThreadLocal
    • Если запись в текущей позиции существует и ключ тот же, текущее значение возвращается напрямую;
    • Если запись в текущем местоположении существует и текущий ключ равен нулю, выполнитеметод чистого сброса
    • Цикл, чтобы получить запись в следующей позиции для сравнения, если ключ в следующей позиции тот же, вернуть значение;
    • Если запись в следующей позиции имеет значение null, это означает, что значение не существует, и выйти из цикла и вернуть null;

метод удаления()

очистить текущийThreadLocalсоответствующийEntryобъект. и позвониметод чистого сброса.

метод чистого сброса

  • интервал обработки: Данные между текущей позицией массива Entry и следующей ненулевой Entry;
  • Очистите запись, ключ которой равен нулю: значение устанавливается равным нулю, а запись устанавливается равной нулю;
  • Сбросьте запись, ключ которой не равен нулю:
    • Получите индекс H массива в входе через хеш-значение ключа;
    • Если h не соответствует индексу текущей записи, сбросить позицию:
      • Установите для входа текущей позиции значение null
      • Начните с h и найдите позицию, в которой первая запись равна нулю.
      • Установите найденную запись в новом месте в качестве исходной записи

Хэш-конфликт

ThreadLocalMapне материализовалсяMapинтерфейс, он не избегает конфликта хэшей в виде связанного списка, а черезотойти назадспособ достижения. При использовании метода set, если текущее местоположение для сохраненияkeyи установитьkeyНепоследовательно, следующая позиция будет оцениваться, пока не будет найденаkeyто же самое илиnullилиEntryдляnullпозиция.

проблема с утечкой памяти

В реальных проектах наши потоки обычно управляются пулом потоков, и потоки всегда будут существовать.ThreadLocalMapЗначение не может быть переработано, вызывая утечку памяти. Чтобы справиться с этой проблемой,ThreadLocalМетоды get() и set() могут очищатьkeyдляnullизEntryобъект. Чтобы быть в безопасности, его следует вызывать вручную, когда мы закончим его использовать.remove()метод очистки данных.

использовать

глобальная переменная

Некоторые данные, такие как идентификатор пользователя, скорее всего, будут использоваться в нескольких методах по всей бизнес-линии, и если они будут передаваться послойно в виде параметров метода, код в целом будет беспорядочным и неэлегантным.ThreadLocalспособ хранения. Обычно он может быть назначен АОП или перехватчиком и вызывается после выполнения бизнес-логики.remove()метод.

private final static ThreadLocal<UserInfo> TL_USER = new ThreadLocal<>();

TL_USER.set(userInfo);

UserInfo userInfo = TL_USER.get();

TL_USER.remove();

Эксклюзивный объект

В реальных проектах мы обычно пишем методы, связанные со временем, в классе инструментов, который часто используется.SimpleDateFormatдля форматирования это небезопасно для потоков. Эксклюзивные объекты могут быть реализованы через ThreadLocal

private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"));

ежедневные комплименты

Это не легко создать, если вы найдете это полезным,попросить лайкслужба поддержки


Поиск внимания

Публичный аккаунт WeChat: Ю Дасянь