该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。(很绕口!!)
我的理解:它本身能够被多个线程共享使用,ThreadLocal类提供了get(),set()方法,在不同的线程中调用它的set方法进行设值(可以简单理解值是保存在一个map中),不会相互影响,因为每个线程拥有独立的"map",值是保存在自己的"map"中的。每个线程都只能获取到自己的"map",因此只有自己才可以通过get来获取设置的值。通过这种方式很好的隔离了多线程执行时对局部变量的操作。
ThreadLocal的几个方法
set(T value) //将此线程局部变量的当前线程副本中的值设置为指定值。
initialValue()
//返回此线程局部变量的当前线程的“初始值”。
remove()
//移除此线程局部变量当前线程的值。
get()
//返回此线程局部变量的当前线程副本中的值。
首先来分析它的set方法源码,当我们需要设值时就需要调用该方法。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
在set方法中首先获取当前正在执行的线程对象,然后获取到ThreadLocalMap对象,可以简单的将他理解为一个map,如果map不为空就将value值保存到map中,其中键是当前的ThreadLocal对象,如果map为空就创建一个并将value保存在其中。前面说过,每一个线程都用于自己的map,进入getMap()可以发现,就是通过当前线程来获取的。
/** * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
如果map为空就会执行createMap(t,value)来创建一个map并将value保存进去。
/** * @param t the current thread * @param firstValue value for the initial entry of the map */ void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue);//1 }
注释//1创建了一个map并保存value,最后将该map赋给当前线程的threadLocals成员变量,下次获取map直接返回这个成员变量的值就好。
当我们需要取值的时候就需要调用它的get()方法,源码如下:
/** * @return the current thread's value of this thread-local */ public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);//1 if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
//1处通过当前线程获取map,获取的map其实就是当前正在执行线程的成员变量,获取到map后如果map不为空就通过map来获取值,获取到值就将它返回。如果获取不到值或者map为空就返回一个默认的初始值,初始值一般为null。setInitialValue()源码如下:
/** * @return the initial value */ private T setInitialValue() { T value = initialValue();//1 Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
很简单,在//1处会直接返回null,这个值就是初始值,然后获取当前正在执行的线程,通过线程来获取自己的map,如果map不为空就将初始值保存进去,为空则创建一个map再将初始值保存进去。
需要注意,一般如果在一个线程中没有调用set方法设值,直接调用get方法,返回的是默认的初始值,如果之前调用了set方法,再调用get方法返回的就是我们设置的值。如果我们希望返回一个我们期望的初始值,可以继承ThreadLocal类来重写它的initialValue()方法。如下
static ThreadLocal tl=new ThreadLocal() { @Override protected Object initialValue() { // TODO Auto-generated method stub return "hello!"; } };
这时如果我们在没有调用set的情况下调用get方法就会返回"hello!"而不会再是null。
最后来看看remove()方法:
/** * Removes the current thread's value for this thread-local variable. * @since 1.5 */ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
很简单,直接移除当前线程map中保存的值。
最后需要注意ThreadLocalMap是ThreadLocal内部的静态类。是通过它来保存和获取值的,而ThreadLocal给我的感觉更像是一个工具类,封装了对ThreadLocalMap的一些操纵。