Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Вивчайте Локальний Потік | Найкращі Практики Багатопотокового Програмування
Багатопотоковість у Java

bookЛокальний Потік

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

ThreadLocalComparison.java

CounterTask.java

CounterTask.java

copy
12345678910111213141516
public 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

ThreadLocalTask.java

ThreadLocalRemoveExample.java

ThreadLocalRemoveExample.java

copy
123456789101112131415161718192021
class 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().

Note
Примітка

Дані, що знаходяться у ThreadLocal, не видаляються самостійно і їх потрібно видаляти явно!

Чому потрібно звільняти значення?

Звільнення значення є важливим для запобігання витокам пам'яті. ThreadLocal зберігає значення, пов'язані з потоками, у спеціальній мапі, яка прив'язана до потоків. Якщо значення не видалити, воно залишається у мапі навіть після завершення використання потоку, що призводить до збереження зайвих об'єктів у пам'яті та, зрештою, до витоків пам'яті.

1. Яку основну проблему вирішує використання ThreadLocal?

2. Яке початкове значення має змінна ThreadLocal при створенні за допомогою методу withInitial()?

3. Що станеться, якщо не викликати метод remove() для змінної ThreadLocal у потоках з тривалим життєвим циклом?

question mark

Яку основну проблему вирішує використання ThreadLocal?

Select the correct answer

question mark

Яке початкове значення має змінна ThreadLocal при створенні за допомогою методу withInitial()?

Select the correct answer

question mark

Що станеться, якщо не викликати метод remove() для змінної ThreadLocal у потоках з тривалим життєвим циклом?

Select the correct answer

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 4. Розділ 4

Запитати АІ

expand

Запитати АІ

ChatGPT

Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат

Suggested prompts:

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

bookЛокальний Потік

Свайпніть щоб показати меню

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

ThreadLocalComparison.java

CounterTask.java

CounterTask.java

copy
12345678910111213141516
public 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

ThreadLocalTask.java

ThreadLocalRemoveExample.java

ThreadLocalRemoveExample.java

copy
123456789101112131415161718192021
class 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().

Note
Примітка

Дані, що знаходяться у ThreadLocal, не видаляються самостійно і їх потрібно видаляти явно!

Чому потрібно звільняти значення?

Звільнення значення є важливим для запобігання витокам пам'яті. ThreadLocal зберігає значення, пов'язані з потоками, у спеціальній мапі, яка прив'язана до потоків. Якщо значення не видалити, воно залишається у мапі навіть після завершення використання потоку, що призводить до збереження зайвих об'єктів у пам'яті та, зрештою, до витоків пам'яті.

1. Яку основну проблему вирішує використання ThreadLocal?

2. Яке початкове значення має змінна ThreadLocal при створенні за допомогою методу withInitial()?

3. Що станеться, якщо не викликати метод remove() для змінної ThreadLocal у потоках з тривалим життєвим циклом?

question mark

Яку основну проблему вирішує використання ThreadLocal?

Select the correct answer

question mark

Яке початкове значення має змінна ThreadLocal при створенні за допомогою методу withInitial()?

Select the correct answer

question mark

Що станеться, якщо не викликати метод remove() для змінної ThreadLocal у потоках з тривалим життєвим циклом?

Select the correct answer

Все було зрозуміло?

Як ми можемо покращити це?

Дякуємо за ваш відгук!

Секція 4. Розділ 4
some-alt