Локальний Потік
ThreadLocal дозволяє уникати механізмів, пов’язаних із багатопотоковістю, таких як синхронізація, оскільки дані з ThreadLocal доступні лише в межах одного потоку.
Уявіть собі банківський застосунок, де кожен клієнт має власний рахунок. Якщо декілька клієнтів одночасно користуються застосунком, їхні рахунки повинні залишатися окремими. Використовуючи ThreadLocal, кожен потік (клієнт) отримує власний екземпляр даних (рахунок), що гарантує відсутність втручання з боку інших потоків.
Як використовувати ThreadLocal
ThreadLocal надає методи get() та set(), які мають очевидне призначення.
get() — отримання значення з змінної ThreadLocal.
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
threadLocal.get();
set() — встановлення значення у змінну ThreadLocal.
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
threadLocal.set(10);
Створимо програму для порівняння звичайної змінної з ThreadLocal.
Кожен потік матиме власний окремий threadLocalCounter, тоді як значення sharedCounter буде змінюватися та використовуватися усіма потоками. Вивід програми продемонструє, що значення threadLocalCounter є унікальними для кожного потоку, тоді як sharedCounter відображає спільний результат для всіх потоків, який може змінюватися залежно від порядку виконання потоків.
ThreadLocalComparison.java
CounterTask.java
12345678910111213141516public class ThreadLocalComparison { public static void main(String[] args) { CounterTask counterTask = new CounterTask(); // Create threads for demonstrating the behavior Thread thread1 = new Thread(counterTask); Thread thread2 = new Thread(counterTask); Thread thread3 = new Thread(counterTask); // Start the threads thread1.start(); thread2.start(); thread3.start(); } }
І після виконання цієї програми ми отримуємо результат:
Shared Counter: 1
Shared Counter: 2
Shared Counter: 3
ThreadLocal Counter: 1
ThreadLocal Counter: 1
ThreadLocal Counter: 1
Як видно, змінна sharedCounter збільшується у різних потоках, тоді як змінна threadLocalCounter зберігає однакове значення в кожному потоці, оскільки кожен потік має власний екземпляр threadLocalCounter, який є незалежним від інших потоків.
Як ви могли помітити, у коді використовується статичний метод ThreadLocal.withInitial(), який встановлює початкове значення для змінної під час її створення.
ThreadLocal<Integer> threadLocalCounter = ThreadLocal.withInitial(() -> 0);
Метод remove() у класі ThreadLocal використовується для видалення значення, пов’язаного з поточним потоком.
ThreadLocalTask.java
ThreadLocalRemoveExample.java
123456789101112131415161718192021class ThreadLocalTask implements Runnable { // Define a `ThreadLocal` variable with an initial value private static ThreadLocal<String> threadLocalValue = new ThreadLocal<>(); @Override public void run() { // Set a value in the `ThreadLocal` for this thread String threadName = Thread.currentThread().getName(); threadLocalValue.set(threadName + " Value"); // Print the current value System.out.println(threadName + " - ThreadLocal Value before removal: " + threadLocalValue.get()); // Remove the value associated with the current thread threadLocalValue.remove(); // Print the value after removal System.out.println(threadName + " - ThreadLocal Value after removal: " + threadLocalValue.get()); } }
У результаті виконання програми:
Thread-0 - ThreadLocal Value before removal: Thread-0 Value
Thread-0 - ThreadLocal Value after removal: null
Thread-1 - ThreadLocal Value before removal: Thread-1 Value
Thread-1 - ThreadLocal Value after removal: null
Програма призначає унікальне значення для ThreadLocal для кожного потоку та відображає це значення до і після виклику методу remove(). Після видалення значення за допомогою remove(), ThreadLocal повертає null при наступних викликах get().
Дані, що знаходяться у ThreadLocal, не видаляються самостійно і їх потрібно видаляти явно!
Чому потрібно звільняти значення?
Звільнення значення є важливим для запобігання витокам пам'яті. ThreadLocal зберігає значення, пов'язані з потоками, у спеціальній мапі, яка прив'язана до потоків. Якщо значення не видалити, воно залишається у мапі навіть після завершення використання потоку, що призводить до збереження зайвих об'єктів у пам'яті та, зрештою, до витоків пам'яті.
1. Яку основну проблему вирішує використання ThreadLocal?
2. Яке початкове значення має змінна ThreadLocal при створенні за допомогою методу withInitial()?
3. Що станеться, якщо не викликати метод remove() для змінної ThreadLocal у потоках з тривалим життєвим циклом?
Дякуємо за ваш відгук!
Запитати АІ
Запитати АІ
Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат
Can you explain more about how ThreadLocal prevents memory leaks?
What are some common use cases for ThreadLocal in real-world applications?
How does ThreadLocal differ from using synchronized blocks or other thread-safety mechanisms?
Awesome!
Completion rate improved to 3.33
Локальний Потік
Свайпніть щоб показати меню
ThreadLocal дозволяє уникати механізмів, пов’язаних із багатопотоковістю, таких як синхронізація, оскільки дані з ThreadLocal доступні лише в межах одного потоку.
Уявіть собі банківський застосунок, де кожен клієнт має власний рахунок. Якщо декілька клієнтів одночасно користуються застосунком, їхні рахунки повинні залишатися окремими. Використовуючи ThreadLocal, кожен потік (клієнт) отримує власний екземпляр даних (рахунок), що гарантує відсутність втручання з боку інших потоків.
Як використовувати ThreadLocal
ThreadLocal надає методи get() та set(), які мають очевидне призначення.
get() — отримання значення з змінної ThreadLocal.
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
threadLocal.get();
set() — встановлення значення у змінну ThreadLocal.
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
threadLocal.set(10);
Створимо програму для порівняння звичайної змінної з ThreadLocal.
Кожен потік матиме власний окремий threadLocalCounter, тоді як значення sharedCounter буде змінюватися та використовуватися усіма потоками. Вивід програми продемонструє, що значення threadLocalCounter є унікальними для кожного потоку, тоді як sharedCounter відображає спільний результат для всіх потоків, який може змінюватися залежно від порядку виконання потоків.
ThreadLocalComparison.java
CounterTask.java
12345678910111213141516public class ThreadLocalComparison { public static void main(String[] args) { CounterTask counterTask = new CounterTask(); // Create threads for demonstrating the behavior Thread thread1 = new Thread(counterTask); Thread thread2 = new Thread(counterTask); Thread thread3 = new Thread(counterTask); // Start the threads thread1.start(); thread2.start(); thread3.start(); } }
І після виконання цієї програми ми отримуємо результат:
Shared Counter: 1
Shared Counter: 2
Shared Counter: 3
ThreadLocal Counter: 1
ThreadLocal Counter: 1
ThreadLocal Counter: 1
Як видно, змінна sharedCounter збільшується у різних потоках, тоді як змінна threadLocalCounter зберігає однакове значення в кожному потоці, оскільки кожен потік має власний екземпляр threadLocalCounter, який є незалежним від інших потоків.
Як ви могли помітити, у коді використовується статичний метод ThreadLocal.withInitial(), який встановлює початкове значення для змінної під час її створення.
ThreadLocal<Integer> threadLocalCounter = ThreadLocal.withInitial(() -> 0);
Метод remove() у класі ThreadLocal використовується для видалення значення, пов’язаного з поточним потоком.
ThreadLocalTask.java
ThreadLocalRemoveExample.java
123456789101112131415161718192021class ThreadLocalTask implements Runnable { // Define a `ThreadLocal` variable with an initial value private static ThreadLocal<String> threadLocalValue = new ThreadLocal<>(); @Override public void run() { // Set a value in the `ThreadLocal` for this thread String threadName = Thread.currentThread().getName(); threadLocalValue.set(threadName + " Value"); // Print the current value System.out.println(threadName + " - ThreadLocal Value before removal: " + threadLocalValue.get()); // Remove the value associated with the current thread threadLocalValue.remove(); // Print the value after removal System.out.println(threadName + " - ThreadLocal Value after removal: " + threadLocalValue.get()); } }
У результаті виконання програми:
Thread-0 - ThreadLocal Value before removal: Thread-0 Value
Thread-0 - ThreadLocal Value after removal: null
Thread-1 - ThreadLocal Value before removal: Thread-1 Value
Thread-1 - ThreadLocal Value after removal: null
Програма призначає унікальне значення для ThreadLocal для кожного потоку та відображає це значення до і після виклику методу remove(). Після видалення значення за допомогою remove(), ThreadLocal повертає null при наступних викликах get().
Дані, що знаходяться у ThreadLocal, не видаляються самостійно і їх потрібно видаляти явно!
Чому потрібно звільняти значення?
Звільнення значення є важливим для запобігання витокам пам'яті. ThreadLocal зберігає значення, пов'язані з потоками, у спеціальній мапі, яка прив'язана до потоків. Якщо значення не видалити, воно залишається у мапі навіть після завершення використання потоку, що призводить до збереження зайвих об'єктів у пам'яті та, зрештою, до витоків пам'яті.
1. Яку основну проблему вирішує використання ThreadLocal?
2. Яке початкове значення має змінна ThreadLocal при створенні за допомогою методу withInitial()?
3. Що станеться, якщо не викликати метод remove() для змінної ThreadLocal у потоках з тривалим життєвим циклом?
Дякуємо за ваш відгук!