Если вы читаете эту статью, вы должны иметь базовое представление о концепции потоков. Если нет, не волнуйтесь, вы можете прочитать мою предыдущую статью
Теперь, когда мы знаем о потоках и о том, как их создавать, мы можем изучить некоторые термины, используемые в концепции потоков. Один из них — ThreadLocal.
В чем польза ThreadLocal?
Когда я изучил концепцию Threads, я начал ее использовать. У меня возникла ситуация, когда я создаю веб-приложение и использовал эту концепцию потока для извлечения данных клиента из базы данных.
У меня есть несколько клиентов, и мне нужно получить только данные, специфичные для клиента. Для этого мне нужна переменная или объект, который может содержать данные, специфичные для клиента, и мы также знаем, что данные каждого клиента извлекаются в каждом потоке.
Теперь у меня есть мысль, что я могу создать объект, специфичный для потока. А вот и концепция ThreadLocal
Способ создания объекта ThreadLocal:
ThreadLocal<Integer> threadLocalValue = new ThreadLocal<>();
Здесь я упомянул Integer, так как мне нужно целочисленное значение. Вы можете указать тип данных в зависимости от ваших потребностей.
Теперь, когда объект создан, я хочу сохранить значение, характерное для моего потока.
threadLocalValue.set(5);
Метод set устанавливает значение threadlocal равным 5, которое внутренне сохраняет значение в виде карты, где ключом является поток, а значение равно 5.
Мы получаем значение следующим образом.
Integer result = threadLocalValue.get();
Мы также можем инициировать значение ThreadLocal, используя статический метод. Здесь создается экземпляр threadlocal с начальным значением 1.
ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);
Мы также можем удалить значение
threadLocal.remove();
Теперь, когда мы все знаем о ThreadLocal, давайте подумаем о сценариях, в которых он вызывает проблему.
У меня есть ThreadPool, где каждый поток назначается клиенту для получения его данных и назначается ThreadLocal. Идеальный!!
Что, если мой поток завершит работу с данными клиента и вернется в пул потоков и подберет другие данные клиента, а предыдущие данные все еще останутся, если мы не сотрем данные должным образом.
Это приведет к проблеме.
Решение для этого, чтобы убедиться, что мы стираем данные, введенные в ThreadLocal потоком, использует метод afterExecute()
public class ThreadLocalAwareThreadPool extends ThreadPoolExecutor { @Override protected void afterExecute(Runnable r, Throwable t) { // Call remove on each ThreadLocal } }
Чтобы использовать метод, мы должны расширить класс ThreadPoolExecutor, который будет выполняться, когда поток будет возвращен в пул потоков.
Большой!!! Надеюсь, вам все ясно с этой концепцией.