import java.util.Random;
public class ThreadLocalTest {
static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 123);
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
Random random = new Random();
while (true) {
int nextInt = random.nextInt();
threadLocal.set(nextInt);
System.out.println("nextInt:" + nextInt + "=" + threadLocal.get());
try {
Thread.currentThread().sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(() -> {
while (true) {
Integer integer = threadLocal.get();
System.out.println("++++++++++++++++++++++++++++++++++++ " + integer);
threadLocal.set(++integer);
try {
Thread.currentThread().sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.start();
thread2.start();
}
}
解析:
- 看到
static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 123);
是定义了一个静态变量threadLocal
thread1
不断地通过threadLocal.set(nextInt);
设置一个随机整数给静态变量threadLocal
thread2
的Integer integer = threadLocal.get();
不断地拿到静态变量threadLocal
中的值
结果:
++++++++++++++++++++++++++++++++++++ 123
nextInt:-1877256441=-1877256441
++++++++++++++++++++++++++++++++++++ 124
nextInt:607964023=607964023
++++++++++++++++++++++++++++++++++++ 125
nextInt:1946708981=1946708981
++++++++++++++++++++++++++++++++++++ 126
nextInt:1558534812=1558534812
++++++++++++++++++++++++++++++++++++ 127
nextInt:97463914=97463914
- 从结果可知,不管线程1如何给同一个静态变量
threadLocal
赋值,线程2都不会拿到线程1设置的值。 - 线程2可以拿到自己线程设置的值。
由此可知threadLocal内部的值是绑定到线程的,
对于需要保证线程安全,也就是变量不被其他线程改变,可以使用threadLocal来做同步。
与synchronized不同的是,使用synchronized
关键字会导致锁等待造成时间上的开销。
使用ThreadLocal
使用的是内存空间的开销。
补充
原理解析:
1、每个存在的线程都维护自己的一个threadLocalMap:
public class Thread {
Map threadLocalMap = new HashMap();
}
2、哪个线程调用ThreadLocal的get、set方法,就从哪个线程内部的threadLocalMap保存或者获取值:
public class ThreadLocal<T> {
public void set(T value) {
Thread currentThread = Thread.getCurrentThread();
currentThread.threadLocalMap.put(this, value);
}
public T get() {
Thread currentThread = Thread.getCurrentThread();
return (T) currentThread.threadLocalMap.get(this);
}
}
测试例子:
public class Test{
public static void main(String[] args) {
Thread t1 = null;
Thread t2 = null;
ThreadLocal<Integer> threadLocal_1 = new ThreadLocal<Integer>();
ThreadLocal threadLocal_2 = new ThreadLocal();
threadLocal_1.set(1);
threadLocal_2.set(2);
Integer value_1 = threadLocal_1.get();//1
Object value_2 = threadLocal_2.get();//2
}
}
一句话:许多个线程都有自己的map对象,ThreadLocal的set方法实际是调用当前运行线程的map的put方法,以ThreadLocal对象作为key,set的值作为value保存。
因此,一个线程内部的map对象可以保存很多个以ThreadLocal对象作为键的键值对。
因此,一个ThreadLocal对象也可以被很多个线程对象的map作为键值对保存。
因此,ThreadLocal对象的get方法拿到的值,取决于是从哪个线程对象的map中拿。
也就是说,同个ThreadLocal对象,可以在每个线程对象中保存一份值。