ThreadLocal类解决的是变量在不同线程间的隔离性,每个线程拥有自己的不同值。Java.lang.ThreadLocal类来实现线程本地存储的功能。ThreadLocal为每个使用该变量的线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量,每个线程内部都会有一个该变量,且在线程内部任何地方都可以使用,线程之间互不影响,这样一来就不存在线程安全问题,也不会严重影响程序执行性能。
每一个线程的Thread对象中都有一个ThreadLocalMap对象,这个对象存储了一组以ThreadLocal.threadLocalHashCode为键,以本地线程变量为值的K-V值对。ThreadLocal对象就是当前线程的ThreadLocalMap的访问入口,每一个ThreadLocal对象都包含了一个独一无二的threadLocalHashCode的值,使用这个值就可以在线程K-V值对中找回对应的本地线程变量。
get()方法是用来获取ThreadLocal在当前线程中保存的变量副本,set()用来设置当前线程中变量的副本,remove()用来移除当前线程中变量的副本,initialValue()是一个protected方法,一般是用来在使用时进行重写的,它是一个延迟加载方法。操作的步骤都是先取得当前线程t,然后通过getMap(t)方法获取到一个map,map的类型为ThreadLocalMap。然后接着下面获取到<key,value>键值对。
总结:实际上通过ThreadLocal创建的副本是存储在每个线程自己内ThreadLocalMap类型对象中的。ThreadLocalMap的键值为ThreadLocal对象的原因是每个线程中可有多个ThreadLocal变量。http://www.cnblogs.com/dolphin0520/p/3920407.html
最常见的ThreadLocal使用场景是用来解决数据库连接、Session管理等。
public class Test {
ThreadLocal<Long> longLocal = new ThreadLocal<Long>();
ThreadLocal<String> stringLocal = new ThreadLocal<String>();
public void set() {
longLocal.set(Thread.currentThread().getId());
stringLocal.set(Thread.currentThread().getName());
}
public long getLong() {
return longLocal.get();
}
public String getString() {
return stringLocal.get();
}
public static void main(String[] args) throws InterruptedException {
final Test test = new Test();
test.set();
System.out.println(test.getLong());
System.out.println(test.getString());
Thread thread1 = new Thread(){
public void run() {
test.set();
System.out.println(test.getLong());
System.out.println(test.getString());
};
};
thread1.start();
thread1.join();
System.out.println(test.getLong());
System.out.println(test.getString());
}
}
输出结果如下:
解释:在这段代码中由两个ThreadLocal变量分别是longLocal和stringLocal,这两个变量在thread1和main线程中都保存了自己的变量副本,且变量的值在两个线程之间相互隔离在每个线程内部,把自己线程内部的longLocal变量和stringLocal变量存储在该线程内部的ThreadLocalMap对象中,在这个ThreadLocalMap对象中存储的内容是ThreadLocal.threadLocalHashCode为键,以本地线程变量为值的K-V值对,例如在上面的例子中thread1内的ThreadLocalMap对象存储的内容是<longLocal对象的hashcode值,thread1线程内的longLocal的值8>,<stringLocal对象的hashcode值,thread1线程内的stringLoccal的值Thread-0>,在main线程内的ThreadLocalMap对象存储的内容是<longLocal对象的hashcode值,main线程内的longLocal的值1>,<stringLocal对象的hashcode值,thread1线程内的stringLoccal的值main>。每个线程内部可以有多个threadLocal变量,在ThreadLocalMap中以ThreadLocal变量的hash值为键,以该值在该线程内部的变量为值的<key,value>对。
补充:使用InheritableThreadLocal类可以让子线程从父线程中取得值,但是继承之后在父线程或子线程中再修改就互不影响了。《Java多线程编程核心技术》
http://qifuguang.me/2015/09/02/[Java并发包学习七]解密ThreadLocal/