ThreadLocal в Java: переменные потока
Last updated: 7 мая 2025 г.ThreadLocal
– переменная ПОТОКА. Это не переменная объекта потока, а именно переменная ПОТОКА. То есть она принадлежит только одному потоку и существует только в одном потоке.
В примере ниже мы создаем объект потока threadDemo
, который передаем на выполнение в три потока. То есть три потока будут работать с одним и тем же объектом.
Если переменная НЕ ThreadLocal и эта переменная в этом объекте меняется каким-то одним потоком, то эта переменная будет измененной и в других потоках, так как они работают с одним и тем же объектом.
Но ThreadLocal переменная не такая. Если ThreadLocal переменную в объекте изменит какой-то один поток, то она не будет измененной в других потоках не смотря на то, что они работают с одним объектом. Она будет измененной только в потоке, который ее изменил.
Пример программы:
1class SomeThread implements Runnable {
2 // локальная переменная объекта класса
3 int counter;
4
5 // локальная переменная потока
6 ThreadLocal<Integer> threadLocalCounter = new ThreadLocal<>();
7
8 // то есть, как видим, есть переменные ОБЪЕКТА,
9 // а есть переменные ПОТОКА.
10 // Смотри более подробно после кода
11
12 public void run() {
13 counter++;
14
15 if (threadLocalCounter.get() != null) {
16 // запись в переменную ThreadLocal
17 // через метод set
18 threadLocalCounter.set(threadLocalCounter.get() + 1);
19 } else {
20 threadLocalCounter.set(0);
21 }
22
23 System.out.println("Counter: " + counter);
24 System.out.println("threadLocalCounter: " + threadLocalCounter.get());
25 }
26}
27
28class ThreadLocalExample {
29 public static void main(String[] args) {
30 SomeThread threadDemo = new SomeThread();
31
32 Thread t1 = new Thread(threadDemo);
33 Thread t2 = new Thread(threadDemo);
34 Thread t3 = new Thread(threadDemo);
35
36 t1.start();
37 try {
38 Thread.sleep(200);
39 } catch (InterruptedException e) {}
40
41 t2.start();
42 try {
43 Thread.sleep(200);
44 } catch (InterruptedException e) {}
45
46 t3.start();
47 }
48}
Вывод:

Как можно увидеть в консоли, переменную counter
меняли все три потока, а переменная threadLocalCounter
была у каждого потока своя личная и в каждом из потоков она только успела стать 0.
Как можно увидеть ThreadLocal иногда не заменим, например в этом случае, когда создать локальную переменную для потока можно только с помощью ThreadLocal, потому что объект один, это threadDemo и все потоки работают с ним, и соответственно, например, локальная переменная counter для всех потоков общая и все потоки изменяют ее в этом объекте, а чтобы создать личную для каждого потока работающего с объектом threadDemo необходимо использовать ThreadLocal.
То есть counter – переменная объекта, threadLocalCounter – переменная потока.
ThreadLocal и потоконебезопасные обьекты
Одним из важных применений ThreadLocal
является работа с потокоНЕбезопасными объектами.
Объекты некоторых классов (например SimpleDateFormat
) потокоНЕбезопасны.
То есть если к одному и тому же объекту SimpleDateFormat
одновременно обращаются несколько потоков, то нужно применять синхронизацию в потоках (используя synchronized например), иначе будет ошибка. Но синхр-я тормозит работу программы. Поможет ThreadLocal.
То есть если объект реализует Runnable, и он будет использоваться многими потоками, и в этом объекте есть потокоНЕбезопасный объект, лучше не использовать синхронизацию, а размножить его на все потоки используя ThreadLocal.
То есть с помощью ThreadLocal можно сделать так, что у каждого потока будет свой объект SimpleDateFormat.
Дополнительные материалы
Следующие уроки
Fork/Join framework в Java
18
мин.
Что такое сериализация в Java
10
мин.
Transient в Java
8
мин.