- 使用ThreadLocal的时候我们保证了每个线程可以隔离使用对象,避免线程间的数据干扰。
常用例子:
public class ThreadLocalTest {
public static void main(String[] args) throws InterruptedException {
ThreadLocal tl=new ThreadLocal();
tl.set("123");
System.out.println(Thread.currentThread()+":"+tl.get());
Thread t=new Thread(
new Runnable() {
public void run() {
tl.set("456");
System.out.println(Thread.currentThread()+":"+tl.get());
}
});
t.start();
Thread.sleep(1000);
System.out.println(Thread.currentThread()+":"+tl.get());
}}
结果:
Thread[main,5,main]:123
Thread[Thread-0,5,main]:456
Thread[main,5,main]:123
从上面的例子可以看出来,每个线程保存的对象是隔离的!
代码分析
下面是Thread里面定义的对象,它的声明是在ThreadLocal里面的一个静态子类对象 ThreadLocal.ThreadLocalMap threadLocals = null;
这里是ThreadLocal的对象定义 static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal>> { /** The value associated with this ThreadLocal. */ Object value; //可以看出key为当前的ThreadLocal对象,value为保存的数据对象 Entry(ThreadLocal> k, Object v) { super(k); value = v; } } }
下面set/get/getMap/createMap方法,可以存储数据
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//根据当前的线程获取数据
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//根据当前的线程获取数据
ThreadLocalMap map = getMap(t);
if (map != null) {
//这里依据对象获取保存的数据
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
/**
* 这里可以看出返回的数据是当前的线程变量
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
从上面可以看出写的代码示例,返回值是不同的因为线程是独立的,
独立线程会有自己的单独数据存储map,
至于ThreadLocal当作key是为了防止多个ThreadLocal在同一个线程当中做区分
ThreadLocal做保存数据的key唯一性
//ThreadLocal类中有一个被final修饰的类型为int的threadLocalHashCode,它在该ThreadLocal被构造的时候就会生成,相当于一个ThreadLocal的ID private final int threadLocalHashCode = nextHashCode(); //threadLocalHashCode值来源于这里 private static AtomicInteger nextHashCode =new AtomicInteger(); private static final int HASH_INCREMENT = 0x61c88647; private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); }