Полностью покорите ThreadLocal: поймите принципы, практическое применение и углубитесь в исходный код! Расширьте InheritableThreadLocal, FastThreadLocal!
Полностью покорите ThreadLocal: поймите принципы, практическое применение и углубитесь в исходный код! Расширьте InheritableThreadLocal, FastThreadLocal!
1. Зачем использовать ThreadLocal

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

Чтобы решить проблему безопасности потоков, обычно используют механизм блокировки, например ключевое слово Synchronized или интерфейс Lock. Однако метод блокировки может привести к снижению производительности, поскольку потокам приходится конкурировать за блокировки, и выполнение потока будет заблокировано во время ожидания блокировки.

Другое решение — использовать ThreadLocal. ThreadLocal предоставляет метод пространства-времени для решения проблем безопасности потоков. Он создает независимое пространство хранения для каждого потока для хранения данных, специфичных для потока. Когда несколько потоков обращаются к одной и той же переменной ThreadLocal, они фактически обращаются к своим соответствующим копиям в локальном хранилище потока, а не к самой общей переменной. Таким образом, каждый поток может изменять свою копию независимо, не затрагивая другие потоки.

Преимущество использования ThreadLocal заключается в том, что оно позволяет избежать конкуренции и блокировки между потоками и повышает производительность параллелизма. В то же время это также упрощает модель программирования, поскольку разработчикам не нужно явно использовать блокировки для защиты доступа к общим переменным.

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

2. Ядро ThreadLocal

ThreadLocalдаJavaсерединаизкласс,это обеспечиваетнитьместный(thread-local)переменная。Этипеременнаяиобычноизпеременнаядругой,потому чтокаждыйдоступпеременнаяизнить У каждого своя независимая инициализация.изпеременнаякопировать。проходитьThreadLocalПример,Может изолировать и сохранять данные каждый раз.,Следите, чтобы нити не мешали друг другу,Избегайте несогласованности данных, вызванной одновременным доступом.

Основные функции
  1. изоляция потока:каждыйнитьверно ThreadLocal переменнаяиз Исправлятьвернодругойнитьда Невидимыйиз。
  2. Нет наследования:ребенокнитьне могудоступотецнитьиз ThreadLocal переменная,Если только в дочернем элементе нет явной операции установки или копирования.
  3. Избегайте синхронизации:потому чтокаждыйнить У каждого есть свойизпеременнаякопировать,Таким образом, синхронизация не требуется для обеспечения безопасности.
Общие методы
  1. public T get():Возвратный токнитьверноотвечатьизпеременнаяизценить。Если в настоящее времянить Нетверноотвечатьизценить,затем возвращает исходное значение или null(еслиеще нетнастраиватьисходныйценить)。
  2. public void set(T value):Установить токнитьверноотвечатьизпеременнаяизценить。
  3. public void remove():удалитьтекущийнитьверноотвечатьизпеременная。
  4. protected T initialValue():этотдазащищенныйизметод,для установкипеременнаяизисходныйценить。в целом,Вы можете переопределить этот метод через анонимный внутренний класс.
Сценарии использования
  1. Подключение к базе данных:существоватьмногопоточностьотвечатьиспользоватьсередина,каждыйнитьможет понадобиться самомуиз Подключение к базе данных。использовать ThreadLocal Может сохранить свое соединение для каждого.
  2. Управление сеансами:существовать Web В приложении могут быть использованы данные каждого пользователя из сеанса. ThreadLocal Хранилище, тем самым гарантируя, что один и тот же пользователь может получить доступ к правильным данным сеанса, когда в одном сеансе обрабатывается несколько запросов.
  3. Внутрипоточная передача контекста:иногда нуженсуществоватьтот же самыйнитьиздругойметодпередавать некоторую контекстную информацию между,а не надеждаиспользоватьобщая ситуацияпеременнаяили передача параметров。этотчас Можетиспользовать ThreadLocal
На что следует обратить внимание
  1. утечка памяти:еслинитьбольше не нужениспользовать Долженпеременная,Но забыл позвонить remove() метод очистки, то потому что ThreadLocalMap серединаиз Entry из key да, верно Thread из слабой ссылки, поэтому Thread После переработки вход из key будет установлено на ноль, но value не будет перерабатываться, что приведет к утечке . Поэтому после использования ThreadLocal После этого лучше позвонить remove() метод очистки.
  2. Использование в бассейне:существоватьнитьбассейнсередина,нитьможет быть использован повторно。еслинить Установить раньше ThreadLocal Если переменная не очищается после использования, следующая задача может прочитать значение настройки предыдущей задачи. Поэтому используется пул существования ThreadLocal Требуется особый уход.
  3. Проблема инициализации:если Не переписывайте initialValue() метод, и существование не вызывается перед использованием set() метод устанавливает значение, затем get() метод вернет null。для Понятноизбегатьэтотдобрый Состояние,Можно переписать initialValue() метод для предоставления значения по умолчанию.
  4. Не применяется к глобальному общему состоянию:Хотя ThreadLocal Может существовать изолировать данные между несколькими нитями,Но это не применимо к глобальному состоянию, которое требует, чтобы существование было разделено между множеством людей и изменялось. Для этой ситуации,отвечать Должениспользоватьдругойсинхронныймеханизм(например, замок или оригиналребенокпеременная)。
3. Принцип работы ThreadLocal

ThreadLocalиз РаботапринципосновнойдапроходитькаждыйнитьвнутреннийизThreadLocalMapосознатьиз。ThreadLocalMapдаThreadLocalизстатическийвнутреннийдобрый,Он реализует что-то вродеMapизключценитьвернохранилищеструктура,нодаключдаслабая ссылка(WeakReference)типизThreadLocalвернослон,И значение зависит от данных.

каждыйнить Есть имяthreadLocalsизчленпеременная,этотиндивидуальныйпеременная СразудаThreadLocalMapтипиз。когданитьвызовThreadLocalизset()методчас,это будетThreadLocalвернослонихранитьизценитьделатьдляключценитьвернодобавить в СобственныйизthreadLocalsсередина。когдавызовget()методчас,нитьпридет от меня самогоизthreadLocalsсерединав соответствии сThreadLocalвернослон查找верноотвечатьизценить。

потому чтокаждыйнить У каждого есть свойизthreadLocals,поэтомуэто Они не будут делиться Этинитьместныйпеременнаяизценить。этот СразудаThreadLocalспособен достичьизоляция причина потока.

4. Использование ThreadLocal

использоватьThreadLocalочень просто,Просто выполните следующие действия:

  1. СоздайтеThreadLocalвернослон:ThreadLocal<T> threadLocal = new ThreadLocal<>();
  2. существовать Нужно установитьнитьместныйпеременнаяизместовызовset()метод:threadLocal.set(value);
  3. существоватьнеобходимо получитьнитьместныйпеременнаяизместовызовget()метод:T value = threadLocal.get();
  4. существоватьбольше не нуженнитьместныйпеременнаячас,вызовremove()метод Очистка ресурсов:threadLocal.remove();

потому чтоThreadLocalсерединаизценитьдаинить Связанныйиз,поэтомусуществоватьиспользоватьнадThreadLocalназад,лучший ичасвызовremove()метод Очистка ресурсов,чтобы избежать потенциальногосуществоватьизутечка памятивопрос。

ThreadLocalотслеживатькаждыйнитьиметь дело сиз Количество задач

первый,определитьTaskCounterдобрый,ДолжендобрыйиспользоватьThreadLocalхранитькаждыйнитьизсчетчик задач:

Язык кода:javascript
копировать
public class TaskCounter {
    // Используйте ThreadLocal для хранения счетчика задач каждый
    private static final ThreadLocal<Integer> taskCountThreadLocal = ThreadLocal.withInitial(() -> 0);

    /**
     * Увеличить счетчик текущих задач
     */
    public static void increment() {
        taskCountThreadLocal.set(taskCountThreadLocal.get() + 1);
    }

    /**
     * Получить текущее значение счетчика задач
     *
     * @return Значение счетчика текущих задач
     */
    public static int getCount() {
        return taskCountThreadLocal.get();
    }

    /**
     * Сбросить счетчик текущих задач
     */
    public static void reset() {
        taskCountThreadLocal.set(0);
    }
}

Затем,СоздайтеWorkerThreadдобрый,Имитируйте выполнение задачи и обновляйте счетчик задач:

Язык кода:javascript
копировать
public class WorkerThread extends Thread {
    private final int taskId;

    public WorkerThread(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {
        System.out.println("Thread " + Thread.currentThread().getId() + " is starting task " + taskId);
        
        // Перед запуском задачи увеличьте счетчик задачи
        TaskCounter.increment();
        
        // Время выполнения задачи моделирования
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        // После завершения задачи распечатать счетчик задач
        System.out.println("Thread " + Thread.currentThread().getId() + " completed task " + taskId + ". Total tasks: " + TaskCounter.getCount());
        
        // Вы можете сбросить счетчик задач здесь или в другое подходящее время.
        // TaskCounter.reset();
    }
}

Наконец, создайте и запустите несколько рабочих потоков в основной программе и наблюдайте за счетчиком задач каждого потока:

Язык кода:javascript
копировать
public class Main {
    public static void main(String[] args) {
        // Создать и открыть 5 вакансий нить
        for (int i = 1; i <= 5; i++) {
            new WorkerThread(i).start();
        }
    }
}

TaskCounterдобрый利использоватьThreadLocalдлякаждыйнитьподдерживал независимуюизсчетчик задач。WorkerThreadдобрыйсуществовать Каждый раз при выполнении задачичас,проходитьвызовTaskCounter.increment()Приходить Увеличить счетчик текущих задач,ипроходитьTaskCounter.getCount()Приходитьполучатьтекущийприлавокизценить。

5. Проблема утечки памяти ThreadLocal

ХотяThreadLocalможет быть эффективно достигнутоизоляция потока,нодаоно также существуетсуществоватьдолженизутечка памятириск。этотосновнойдапотому чтоThreadLocalMapсерединаизключдаслабая ссылкатипизThreadLocalвернослон。когдаThreadLocalвернослон Нет再одеялосильная ссылкачас,Его соберет сборщик мусора.,нода, верноотвечатьизключценитьверновсе ещебронироватьсуществоватьThreadLocalMapсередина。еслинитьдлинныйчасбегать между且Нетвызовremove()метод Очистка ресурсов,Тогда эти бесполезные пары ключ-значение будут занимать место в памяти.,что приводит к утечке памяти。

Чтобы избежать этой проблемы, мы можем принять следующие меры:

  1. существоватьиспользоватьнадThreadLocalназад,ичасвызовremove()метод Очистка ресурсов。
  2. использоватьстатическийвнутреннийдобрый ПриходитьдержатьThreadLocalвернослон,чтобы гарантировать, что он не будет переработан преждевременно.
  3. Старайтесь избегатьсуществоватьдлинныйчасбегать междуизнитьсерединаиспользоватьThreadLocal
  4. Использование Java 8представлятьизInheritableThreadLocalПриходитьзаменятьThreadLocal,он можетсуществоватьребенокнитьсередина自动继承отецнитьизнитьместныйпеременнаяценить,Это позволяет избежать проблемы повторной установки значений, когда существующее создает новую нить. Но также необходимо уделять внимание своевременной очистке ресурсов, чтобы избежать утечки памяти.
6. Анализ исходного кода

ThreadLocal да Java серединаиспользовать В创建нитьместныйпеременнаяиздобрый。нитьместныйпеременнаядакаждыйнить У каждого есть свойнезависимый Примеризпеременная,идругойнитьиз Примеризолированы друг от друга。подда, верно ThreadLocal Краткий анализ исходного кода.

Основные переменные-члены
  • ThreadLocalMap threadLocals:этотда Thread Поле в классе, которое используется для хранения локальных переменных. Это не так. ThreadLocal Класс является прямым членом, но реализует изоляцию. потокизKey.
  • ThreadLocalMap inheritableThreadLocals:такой жесуществовать Thread добрыйсередина,используется для хранения наследуемыхизнитьместныйпеременная。

существовать ThreadLocal Внутри класса нет прямых ссылок на эти поля, и доступ к текущему нитиз осуществляется через статические методы. threadLocals поле.

ThreadLocal Он не хранит данные напрямую, но, как класс инструмента, предоставляет методы для доступа и работы с локальными переменными. Фактически данные хранятся ThreadLocal внутренний класс ThreadLocalMap завершить. каждый Thread Объекты содержат объект с именем threadLocals из ThreadLocalMap Тип переменной-члена, эта переменная используется для хранения всех текущих значений. ThreadLocal Объект из ценности.

Вот краткое содержание ThreadLocalThreadLocalMap и Thread Отношения между из:

  1. ThreadLocal:этотда一индивидуальный工具добрый,предоставил set(T value)get() и remove() ждатьметод Приходить操делатьнитьместныйпеременная。нода,Он не хранит данные непосредственно сам.
  2. ThreadLocalMap:этотда ThreadLocal статический внутренний класс, на самом деле это настраиваемая хеш-таблица (но не java.util.HashMap)。он используется для хранениянитьместныйпеременнаяизценить,икаждыйнить Все有一индивидуальныйэтот Образецизкартографирование.этотиндивидуальный映射изключда ThreadLocal вернослон,ценитьда, верноотвечатьизнитьместныйпеременнаяизценить。
  3. Thread:Java серединаизнитьдобрый。каждый Thread Каждый объект имеет threadLocals поле, это да ThreadLocalMap Экземпляр, используемый для хранения всех ThreadLocal Текущее значение переменной из. Когда нит звонит ThreadLocal из set метод, он на самом деле дасуществовать себя из threadLocals Устанавливает значение в карте при вызове; get метод, он да из себя из threadLocals Получить значение с карты.

Такая конструкция позволяет каждыйнить управлять собой самостоятельно. ThreadLocal переменная,Скорее, чемидругойнитьизпеременнаяпроисходит конфликт。этотдамногопоточностьпрограммированиесередина一индивидуальный Нет常有использоватьизхарактеристика,Потому что это позволяет разработчикам поддерживать безопасное состояние без использования явных блокировок.

основной метод

get()

Язык кода:javascript
копировать
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

get() Метод сначала получает текущий нить, а затем пытается получить текущий нитьиз из threadLocals Получить с поля ThreadLocalMap。еслиподключенное хранилищесуществоватьи содержиттекущий ThreadLocal Экземпляр записи, возвращается соответствующее значение. В противном случае позвоните setInitialValue() чтобы установить начальное значение.

set(T value)

Язык кода:javascript
копировать
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

set() Метод устанавливает заданное значение в текущее значение. threadLocals поле, соответствующее текущему ThreadLocal Пример ключа.если Картирования не существуетсуществовать,но Создайтеновыйизкартографирование.

remove()

Язык кода:javascript
копировать
public void remove() {
    ThreadLocalMap m = getMap(Thread.currentThread());
    if (m != null)
        m.remove(this);
}

remove() Метод из текущего нитиз threadLocals Удалить текущий ThreadLocal Экземпляры соответствуют из записей.

initialValue()

Язык кода:javascript
копировать
protected T initialValue() {
    return null;
}

initialValue() Методда ThreadLocal защищённый метод, возвращающий начальное значение переменной. По умолчанию он возвращает null,Но подклассы могут переопределить этот метод, чтобы предоставить собственное начальное значение.

Вспомогательный метод
  • getMap(Thread t):получатьнить t из threadLocals картографирование.
  • createMap(Thread t, T firstValue):существоватьнить t Создать новый из в ThreadLocalMap,и устанавливает заданное значение на карту,верноотвечать Втекущий ThreadLocal Пример ключа.
  • setInitialValue():этотиндивидуальныйметодпервыйвызов initialValue() чтобы получить начальное значение, а затем вызвать set() Метод устанавливает это начальное значение в текущую карту нитиз. Это стратегия ленивой инициализации.
ThreadLocalMap

ThreadLocalMap да Специальная реализация хэш-таблицы, специально используемая для хранения локальных переменных. это изкейда ThreadLocal вернослон,ценитьда, верноотвечатьизнитьместныйпеременнаяизценить。этотиндивидуальный映射из Реализация очень особенная.,Он использует открытую адресацию и линейное зондирование для разрешения коллизий хэшей.

каждый ThreadLocalMap Экземпляры не связаны ни с чем, поэтому их не нужно учитывать при синхронизации. Это также означает, что не будет одновременного доступа к сопоставлению между различными изницами, что обеспечивает изоляцию. потока。

Суммируя, ThreadLocal Поддерживать независимость из-за существованиякаждыйнить ThreadLocalMap для достижения изоляции потоков. Это отображение начинается с ThreadLocal Экземпляры — это ключи, в которых хранятся уникальные данные. Получите доступ к текущему сопоставлению нитиз через статические методы и убедитесь, что каждый может получать доступ и изменять только свое собственное сопоставление, тем самым достигая изоляции локальной переменной.

7. InheritableThreadLocal расширения ThreadLocal

InheritableThreadLocal да ThreadLocal изExtension. и ThreadLocal каждыйнитьдержать себя в рукахизнезависимыйценитькопироватьдругой,InheritableThreadLocal Есть функция, дающая при создании нового изнить, если в родительском есть нить. InheritableThreadLocal переменная,Такребенокнить Воля Унаследуетэтотиндивидуальныйпеременнаяизценить。этотиметь в видуребенокнить Можетдоступ Чтоотецнитьдляэтотдобрыйпеременнаянастраиватьизценить。

Эта функция существования очень полезна в определенных сценариях.,Например, если вы хотите поделиться определенными данными по всему дереву нить.,Но мы не хотим, чтобы к этим данным получили доступ другие нерелевантные пользователи. Однако,Необходимо использовать с осторожностью,Потому что неправильное использование из может привести к загрязнению данных-памяти.

использование

Язык кода:javascript
копировать
public class InheritableThreadLocalExample {
    
    // Создайте InheritableThreadLocal переменная
    private static final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();

    public static void main(String[] args) {
        // существоватьхозяиннитьсерединанастраиватьценить        inheritableThreadLocal.set("Это родительское значение");
        
        System.out.println("Родительское значение: " + inheritableThreadLocal.get());
        
        // Создайтеребенокнить
        Thread childThread = new Thread(() -> {
            // Попытка получить значение в существующем суб-нии, за счет использования InheritableThreadLocal, здесь вы получите значение, установленное в родительском элементе.
            System.out.println("суб.значение: " + inheritableThreadLocal.get());
        });
        
        // промоутерить
        childThread.start();
        
        // Дождитесь завершения выполнения дочернего элемента
        try {
            childThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        // Очистите значение, когда основное значение закончится, чтобы предотвратить скрытое существованиеизутечка. памяти
        inheritableThreadLocal.remove();
    }
}

Создал InheritableThreadLocal переменная,А существование основной нити задает строковое значение. Затем мы создали,исуществоватьребенокнитьиз run Напечатайте это значение в методе. Поскольку мы используем изда InheritableThreadLocal,Дочерний нит может получить доступ к значению из, установленному в родительском нит. поэтому,Вывод покажет, что и родительский, и дочерний элемент имеют доступ к этому значению.

когда больше не нужен InheritableThreadLocal переменные, мы используем remove() Способы его очистки, чтобы предотвратить потенциальное существование изютечки памяти。

8. FastThreadLocal оптимизации ThreadLocal

FastThreadLocal да Netty Структура обеспечиваетизвысокая производительностьизнитьместныйпеременнаявыполнить,его цельсуществоватьпредоставить, чем Java Стандартная библиотека ThreadLocal Более высокая скорость доступа.

FastThreadLocal проходитьиспользоватьвнутренниймножествоипеременнаяиндекстехнология减少Понятнодоступнитьместныйпеременнаяизчасмежду,улучшенная производительность。этотдобрыйвыполнить Особенно подходит длясуществоватьвысокая частотадоступнитьместныйпеременнаяизсценасерединаиспользовать。

FastThreadLocal изосновной Преимуществасуществоватьблагодаря высокой эффективностииз Памятьдоступмодельи Сокращение косвенных ссылок,Это помогает уменьшить промахи в кэше.,И улучшить локальность доступа к памяти. Однако,Необходимо обратить внимание на,FastThreadLocal Основными из них являются Netty Предназначен для внутреннего использования, но может использоваться и просто так или иначе. Java приложение, хотя может потребоваться дополнительная настройка.

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

Язык кода:javascript
копировать
import io.netty.util.concurrent.FastThreadLocal;
import io.netty.util.concurrent.FastThreadLocalThread;

public class FastThreadLocalExample {

    // Создайте FastThreadLocal переменная
    private static final FastThreadLocal<String> fastThreadLocal = new FastThreadLocal<>();

    public static void main(String[] args) {
        // потому что FastThreadLocal да Netty Дизайн из, это обычно и Netty изнить модель, используемую вместе.
        // нодля Понятно演示,нас Приходить Создайте FastThreadLocalThread имитировать Netty изнить。
        FastThreadLocalThread thread = new FastThreadLocalThread(() -> {
            // существоватьнитьсерединанастраиватьценить            fastThreadLocal.set("FastThreadLocal Среднее значение");

            // Получить и распечатать значения
            System.out.println("нитьсерединаизценить: " + fastThreadLocal.get());

            // Очистить значение для предотвращения утечки памяти
            fastThreadLocal.remove();
        });

        // запускатьнить        thread.start();
    }
}

Однако приведенный выше код не является типичным. FastThreadLocal использование,Просто покажи, как существовать не Netty среда. существоватьистинаиз Netty В приложениях он обычно используется при обработке сетевых событий. FastThreadLocal,Напримерсуществовать ChannelHandler Хранение, извлечение и конкретизация Channel Связано со статусом.

еслисуществовать Нет Netty Нить (т.е. не FastThreadLocalThread)серединаиспользовать FastThreadLocal,Вам необходимо вручнуювызов FastThreadLocal.initialize(Thread) метод Приходитьисходный化нитьизместныйпеременнаяхранилище。нода,существовать Netty В среде все это обрабатывается автоматически.

и ThreadLocal То же самое, когда больше не нуженнитьместныйпеременнаячас,отвечать Долженвызов remove() Способы его очистки, чтобы предотвратить потенциальное существование изютечки . Это существование особенно важно для длительной работы приложений в пуле.


9. Вопросы на собеседовании, связанные с ThreadLocal

нижедачто-то оThreadLocalиз Распространенные вопросы на собеседовании и их Отвечать:

Вопрос собеседования 1: Пожалуйста, объясните, что такое ThreadLocal и его цель?

Отвечать

ThreadLocalдаJavaсерединаизкласс,это обеспечиваетнитьместный(thread-local)переменная。Этипеременнаяиобычноизпеременнаядругой,потому чтокаждыйдоступпеременнаяизнить У каждого своя независимая инициализация.изпеременнаякопировать。ThreadLocalПримерв целомдадобрыйсерединаиз Частные статические поля,Они используются для сохранения уникального государства, принадлежащего нити.,Например, пользовательID、делаIDждать。проходитьиспользоватьThreadLocal,Вы можете избежать использования синхронизации в среде многопоточности.,Тем самым улучшая производительность программы.

Вопрос собеседования 2: Как ThreadLocal реализует локальное хранилище потоков?

Отвечать

ThreadLocalвнутреннийиспользовать Понятно一индивидуальный称дляThreadLocalMapиз Пользовательская хэш-карта,хранитьнитьместныйпеременная。каждыйThreadКаждый объект имеетиотношениеизThreadLocalMap,этотиндивидуальный映射ВоляThreadLocalвернослонделатьдляключ,Волянитьместныйпеременнаяизценитьделатьдляценить。когданитьвызовThreadLocalизsetметодчас,это будетсуществовать СобственныйизThreadLocalMapсерединахранилище一индивидуальныйключценитьверно;вызовgetметодчас,этопридет от меня самогоиз Получить значение с карты.потому чтокаждыйнить У каждого есть свойизThreadLocalMap,Таким образом, они могут хранить и извлекать значения независимо.,Без и других нит конфликтов.

Вопрос собеседования 3: Какие проблемы может вызвать ThreadLocal?

Отвечать

ThreadLocalиспользовать Неткогдаможет привести кутечка памятиизагрязнение данныхвопрос。

  • утечка памяти:еслинитьбольше не нужен,Но ни один пул не будет использовать его повторно.,и Доизнитьнастраивать ПонятноThreadLocalпеременнаяно Нет Прозрачный,Так Этипеременная Может занимать память, которую сборщик мусора не может освободить.。этот Можетпроходитьсуществоватьбольше не нуженThreadLocalпеременнаячасвызов Чтоremoveметод Приходитьизбегать。
  • загрязнение данных:когданитьодеялонитьбассейн重использоватьчас,если Доиз任务Нет Прозрачный ЧтонастраиватьизThreadLocalпеременная,Тогда новые задачи могут случайно получить доступ к этим старым данным. Чтобы избежать этой ситуации,отвечать Долженсуществоватькаждый Миссия начинаетсячас Очистить возможносуществоватьизThreadLocalпеременная。
Вопрос на собеседовании 4: В чем разница между ThreadLocal и синхронизированным?

Отвечать

ThreadLocalиsynchronizedВседаиспользовать Виметь дело смногопоточностьпрограммированиесерединаобщие ресурсыдоступвопросизтехнология,Но они работают в разных сценариях применения.

  • ThreadLocal:это обеспечиваетнитьместныйпеременная,каждыйнить Все有Что Собственныйизпеременнаякопировать。этот Образец,нит может самостоятельно оперировать своими данными,без необходимостиидругойнитьсинхронный。ThreadLocalПрименимо ккаждыйнитьнуждатьсянезависимый保жить Собственныйсостояниеиз Состояние。
  • synchronized:этодавстроенныйизсинхронныймеханизм,использовать В控制нескольконитьвернообщие ресурсыиздоступ。проходитьиспользоватьsynchronizedзакрыватьключ Характер,Может гарантировать, что только один нит может одновременно выполнять определенный блок кода или метод.,тем самым избегаянить Безопасностьвопрос。synchronizedПрименимо кнескольконитьнужно поделитьсяи协делатьдоступтот же ресурсиз Состояние。
Вопрос на собеседовании 5: Почему ThreadLocal вызывает утечки памяти?

Отвечать

ThreadLocal вызывает утечку памятиизосновнойпричинасуществовать ВЧтовнутреннийдобрыйThreadLocalMapсерединаизключценитьверно可能Нет会одеяло Сборщик мусора собирает правильно。ThreadLocalMapдаThreadдобрыйиз一индивидуальныйчленпеременная,использовать Вхранилищекаждыйнить СобственныйизThreadLocalпеременнаякопировать。

каждыйThreadLocalПримерсуществоватьThreadLocalMapсерединаделатьдляключжитьсуществовать,и связаны по значению, чтобы данные были уникальными. Когда данные больше не нужны,и Нетявный地вызовThreadLocalизremove()метод Приходить Прозрачныйэтоихчас,Этиключценитьверновсе ещебронироватьсуществоватьThreadLocalMapсередина。

Если нитьда работает в течение длительного времени (например, нить пул изнить),Тогда эти неочищенные пары ключ-значение будут долго занимать память. хуже изда,еслиThreadLocalПримерсамда一индивидуальный匿名внутреннийдобрый或者статическийдобрыйиз Пример,и содержит ссылку на внешний класс из,Тогда экземпляр внешнего класса не может быть подвергнут сборке мусора.,Это приводит к более серьезным симптомам.

также,Даже если нить в конце концов прекратится,Threadвернослонсам(以иэтоизThreadLocalMap)可能也Нет会立即одеялосбор мусора,Особенно дасуществовать используется в случае нить пула из. поэтому,длинныйчасмежду НетубиратьизThreadLocalпеременнаяможет вызватьотвечатьиспользовать程序из Доступная память постепенно уменьшается,в конечном итоге приводит кOutOfMemoryError

Чтобы избежать этой утечки памяти,лучшие практикидасуществоватьбольше не нуженThreadLocalпеременнаячасявныйвызов Чтоremove()метод。этот确保ПонятноитекущийнитьассоциацияизThreadLocalMapсерединаиз Взаимноотвечатьвхододеялоправильныйудалить,Это позволяет сборщику мусора освободить связанную память. существования Это особенно важно при использовании нить-пула.,Потому что нить можно использовать повторно,иэтоихизThreadLocalMapтакже будет сохранен。

Вопрос на собеседовании 6: Почему ключи ThreadLocal должны использовать слабые ссылки?

Отвечать

ThreadLocalизkeyиспользоватьслабая ссылкаизосновнойглазиздачтобы помочь избежатьутечка памяти。существоватьJavaсередина,слабая ссылка(WeakReference)да一добрый引использоватьтип,Это не предотвращает переработку объекта, на который он ссылается, сборщиком мусора. Когда работает сборщик мусора,Если обнаружено, что на объект ссылаются только слабые ссылки,Затем он переработает объект.

существоватьThreadLocalMapсередина,keyдаThreadLocalвернослон,valueдаинить Связанныйизценить。еслиThreadLocalизkeyиспользоватьсильная ссылка,Тогда, пока нить объекта хранится в существующем состоянии (например, нить пула изнить),,Несмотря на тоThreadLocalПримерсуществоватьдругойместо已经Нетодеяло引использовать,Он также не будет утилизирован сборщиком мусора.,потому чтоThreadLocalMapсередина还держатьверноэтоизсильная ссылка。этотдобрый Состояние Вниз,еслиThreadLocalвернослондержать Понятнодругойресурс(такой же большой, каквернослон、Подключение к базе данныхждать),Так Этиресурс也не будет перерабатываться, что приведет к утечке памяти。

проходитьиспользоватьслабая ссылкаделатьдляThreadLocalMapсерединаизkey,когдаThreadLocalПримерсуществоватьдругойместо Нет再одеяло引использоватьчас,Сборщик мусора может его вернуть. так,Несмотря на тонить Все еще существуютсуществовать,иотношениеизThreadLocalвернослон也Можетодеялоубирать,Тем самым высвобождая имеющиеся в нем ресурсы. Однако,Необходимо обратить внимание на,Просто установить ключ на слабую ссылку недостаточно, чтобы полностью избежать утечки памяти. Если само значение содержит другие ресурсы, утечка которых не допускается.,Тогда эти ресурсы все равно могут быть утекли. поэтому,правильныйиспользоватьThreadLocal(включатьсуществоватьбольше не нуженчасвызовremove()метод)все ещедаизбегатьутечка памятииззакрыватьключ。

кроме того,Примечательное изда,Хотя слабые ссылки помогают снизить риск утечки памяти.,Но это также приносит некоторые сложности. Например,существоватьThreadLocalMapизвыполнитьсерединануждатьсяиметь дело сkeyодеялослучайная переработкаиз Состояние。поэтому,существуют При проектировании структур данных, таких как из, приходится идти на компромиссы.

10. Напишите резюме

ThreadLocalдаJavaи发программированиесередина Нет Очень важноизкласс,это обеспечиваетнитьместныйпеременнаяиз Функция,делатькаждыйнить Все Может拥有Собственныйнезависимыйизпеременнаякопировать。проходить深入Понятно解ThreadLocalиз Работапринципииспользование,Мы можем лучше применить его для решения проблем параллельного программирования. в то же время,Также необходимо обратить вниманиеThreadLocalизутечка проблемы с памятью и примите соответствующие меры, чтобы избежать возникновения этой проблемы.


Навыки обновляются благодаря обмену ими, и каждый раз, когда я получаю новые знания, мое сердце переполняется радостью. Искренне приглашаем вас подписаться на публичный аккаунт код тридцать пять , для получения дополнительной технической информации.

boy illustration
RasaGpt — платформа чат-ботов на основе Rasa и LLM.
boy illustration
Nomic Embed: воспроизводимая модель внедрения SOTA с открытым исходным кодом.
boy illustration
Улучшение YOLOv8: EMA основана на эффективном многомасштабном внимании, основанном на межпространственном обучении, и эффект лучше, чем у ECA, CBAM и CA. Малые цели имеют очевидные преимущества | ICASSP2023
boy illustration
Урок 1 серии Libtorch: Тензорная библиотека Silky C++
boy illustration
Руководство по локальному развертыванию Stable Diffusion: подробные шаги и анализ распространенных проблем
boy illustration
Полностью автоматический инструмент для работы с видео в один клик: VideoLingo
boy illustration
Улучшения оптимизации RT-DETR: облегченные улучшения магистрали | Support Paddle облегченный rtdetr-r18, rtdetr-r34, rtdetr-r50, rtdet
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | Деформируемое внимание с большим ядром (D-LKA Attention), большое ядро ​​​​свертки улучшает механизм внимания восприимчивых полей с различными функциями
boy illustration
Создано Datawhale: выпущено «Руководство по тонкой настройке развертывания большой модели GLM-4»!
boy illustration
7B превышает десятки миллиардов, aiXcoder-7B с открытым исходным кодом Пекинского университета — это самая мощная модель большого кода, лучший выбор для корпоративного развертывания.
boy illustration
Используйте модель Huggingface, чтобы заменить интерфейс внедрения OpenAI в китайской среде.
boy illustration
Оригинальные улучшения YOLOv8: несколько новых улучшений | Сохранение исходной информации — алгоритм отделяемой по глубине свертки (MDSConv) |
boy illustration
Второй пилот облачной разработки | Быстро поиграйте со средствами разработки на базе искусственного интеллекта
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция с нулевым кодированием и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
Решенная Ошибка | Загрузка PyTorch медленная: TimeoutError: [Errno 110] При загрузке факела истекло время ожидания — Cat Head Tiger
boy illustration
Brother OCR, библиотека с открытым исходным кодом для Python, которая распознает коды проверки.
boy illustration
Новейшее подробное руководство по загрузке и использованию последней демонстрационной версии набора данных COCO.
boy illustration
Выпущен отчет о крупной модели финансовой отрасли за 2023 год | Полный текст включен в загрузку |
boy illustration
Обычные компьютеры также могут работать с большими моделями, и вы можете получить личного помощника с искусственным интеллектом за три шага | Руководство для начинающих по локальному развертыванию LLaMA-3
boy illustration
Одной статьи достаточно для анализа фактора транскрипции SCENIC на Python (4)
boy illustration
Бросая вызов ограничениям производительности небольших видеокарт, он научит вас запускать большие модели глубокого обучения с ограниченными ресурсами, а также предоставит полное руководство по оценке и эффективному использованию памяти графического процессора!
boy illustration
Команда Fudan NLP опубликовала 80-страничный обзор крупномасштабных модельных агентов, в котором в одной статье представлен обзор текущего состояния и будущего агентов ИИ.
boy illustration
[Эксклюзив] Вы должны знать о новой функции JetBrains 2024.1 «Полнострочное завершение кода», чтобы решить вашу путаницу!
boy illustration
Краткое изложение базовых знаний о регистрации изображений 1.0
boy illustration
Новейшее подробное руководство по установке и использованию библиотеки cv2 (OpenCV, opencv-python) в Python.
boy illustration
Легко создайте локальную базу знаний для крупных моделей на основе Ollama+AnythingLLM.
boy illustration
[Решено] ошибка установки conda. Среда решения: не удалось выполнить первоначальное зависание решения. Повторная попытка с помощью файла (графическое руководство).
boy illustration
Одна статья поможет вам понять RAG (Retrival Enhanced Generation) | Введение в концепцию и теорию + практику работы с кодом (включая исходный код).
boy illustration
Эволюция архитектуры шлюза облачной разработки
boy illustration
Docker и Kubernetes [Разработка контейнерных приложений с помощью Python]