我们再来看看get方法
public T get() {
Thread t = Thread.currentThread();//1.首先获取当前线程
ThreadLocalMap map = getMap(t);//2.获取线程的map对象
if (map != null) {//3.如果map不为空,以threadlocal实例为key获取到对应Entry,然后从Entry中取出对象即可。
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();//如果map为空,也是第一次没有调用set直接get(或者调用过set,又调用了remove)时,为其设定初始值
}
  setInitialValue
1  private T setInitialValue() {
2         T value = initialValue();//获取初始值
3         Thread t = Thread.currentThread();
4         ThreadLocalMap map = getMap(t);
5         if (map != null)
6             map.set(this, value);
7         else
8             createMap(t, value);
9         return value;
10     }
  initialValue方法,默认是null,访问权限是protected,即允许重写。
  1 protected T initialValue() {
  2         return null;
  3     }
  谈到这儿,我们应该已经对ThreadLocal的设计目的及设计思想有一定的了解了。
  线程独享变量?
  还有一个会引起疑惑的问题,我们说ThreadLocal为每一个线程维护一个独立的变量副本,那么是不是说各个线程之间真正的做到对于对象的“完全自治”而不对其他线程的对象产生影响呢?其实这已经不属于对于ThreadLocal的讨论,而是你出于何种目的去使用ThreadLocal。如果我们为一个线程关联的对象是“完全独享”的,也是每个线程拥有一整套的新的 栈中的对象引用+堆中的对象,那么这种情况下是真正的彻底的“线程独享变量”,相当于一种深度拷贝,每个线程自己玩自己的,对该对象做任何的操作也不会对别的线程有任何影响。
  另一种更普遍的情况,所谓的独享变量副本,其实也是每个线程都拥有一个独立的对象引用,而堆中的对象还是线程间共享的,这种情况下,自然还是会涉及到对共享资源的访问操作,依然会有线程不安全的风险。所以说,ThreadLocal无法解决线程安全问题。
  所以,需不需要完全独享变量,进行完全隔离,取决于你的应用场景了。可以想象,对象过大的时候,如果每个线程都有这么一份“深拷贝”,并发又比较大,对于服务器的压力自然是很大的。像web开发中的servlet,servlet是线程不安全的,一请求一线程,多个线程共享一个servlet对象;而早期的CGI设计中,N个请求对应N个对象,并发量大了之后性能自然很差。

  ThreadLocal在spring的事务管理,包括Hibernate的session管理等都有出现,在web开发中,有时会用来管理用户会话 HttpSession,web交互中这种典型的一请求一线程的场景似乎比较适合使用ThreadLocal,但是需要特别注意的是,由于此时session与线程关联,而tomcat这些web服务器多会采用线程池机制,也是说线程是可复用的,所以在每一次进入的时候都需要重新进行set,或者在结束时及时remove。