1.概述
ThreadLocal,很多地方叫做线程本地变量,也有些地方叫做线程本地存储,ThreadLocal 的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。
ThreadLocal是除了加锁这种同步方式之外的一种保证一种规避多线程访问出现线程不安全的方法,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。
ThreadLocal是JDK包提供的,它提供线程本地变量,如果创建一乐ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个副本,在实际多线程操作的时候,操作的是自己本地内存中的变量,从而规避了线程安全问题
ThreadLocalMap(线程的一个属性)
- 每个线程中都有一个自己的 ThreadLocalMap 类对象,可以将线程自己的对象保持到其中,
各管各的,线程可以正确的访问到自己的对象。 - 将一个共用的 ThreadLocal 静态实例作为 key,将不同对象的引用保存到不同线程的
ThreadLocalMap 中,然后在线程执行的各处通过这个静态 ThreadLocal 实例的 get()方法取
得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。 - ThreadLocalMap 其实就是线程里面的一个属性,它在 Thread 类中定义
ThreadLocal.ThreadLocalMap threadLocals = null;
2. 使用场景
最常见的 ThreadLocal 使用场景为用来解决 数据库连接、Session 管理等。
3. demo
public class TestThreadLocal {
private static final ThreadLocal<Map<String, String>> threadLocal = new ThreadLocal<>();
/**
* itl 支持父线程的本地变量传递给子线程这种基本操作,线程池方式不支持
*/
private static final ThreadLocal<Map<String, String>> threadLocal1 = new InheritableThreadLocal<>();
/**
* ttl 所以TTL一定是支持父线程的本地变量传递给子线程这种基本操作的,ITL也可以做到,但是前面有讲过,ITL在线程池的模式下,
* 就没办法再正确传递了,所以TTL做出的改进就是即便是在线程池模式下,也可以很好的将父线程本地变量传递下去,
*/
private static final ThreadLocal<Map<String, String>> threadLocal2 = new TransmittableThreadLocal<>();
public static Map<String, String> getMap() {
if (threadLocal.get() == null) {
threadLocal.set(new ConcurrentHashMap<>());
}
return threadLocal.get();
}
public static void main(String[] args) throws InterruptedException {
Map<String, String> map = getMap();
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
map.put(String.valueOf(i), String.valueOf(i));
}
}
threadLocal.set(map);
threadLocal2.set(map);
System.out.println(Thread.currentThread().getName()+"threadLocal:" + threadLocal.get());
System.out.println(Thread.currentThread().getName()+"threadLocal2:" + threadLocal2.get());
Runnable r = () -> {
Map<String, String> map1 = getMap();
if (map != null && map1.size() == 0) {
map1.put("1", "1");
}
threadLocal.set(map1);
threadLocal2.set(map1);
System.out.println(Thread.currentThread().getName()+"threadLocal:" + threadLocal.get());
System.out.println(Thread.currentThread().getName()+"threadLocal2:" + threadLocal2.get());
};
Thread t = new Thread(r);
t.start();
Thread.sleep(900);
System.out.println(Thread.currentThread().getName()+"threadLocal:" + threadLocal.get());
System.out.println(Thread.currentThread().getName()+"threadLocal2:" + threadLocal2.get());
}
}
结果
两个红色框说明了,ttl父进程的的值传递到了子线程!
两个蓝色框表明了,子线程的值不会意污染父进程的值!