- 使用ThreadLocal的时候我们保证了每个线程可以隔离使用对象,避免线程间的数据干扰。
常用例子:
1public class ThreadLocalTest { 2 3 public static void main(String[] args) throws InterruptedException { 4 ThreadLocal tl=new ThreadLocal(); 5 tl.set("123"); 6 System.out.println(Thread.currentThread()+":"+tl.get()); 7 8 Thread t=new Thread( 9 new Runnable() { 10 public void run() { 11 tl.set("456"); 12 System.out.println(Thread.currentThread()+":"+tl.get()); 13 } 14 }); 15 t.start(); 16 Thread.sleep(1000); 17 System.out.println(Thread.currentThread()+":"+tl.get()); 18}} 19 20结果: 21 22Thread[main,5,main]:123 23Thread[Thread-0,5,main]:456 24Thread[main,5,main]:123 25
从上面的例子可以看出来,每个线程保存的对象是隔离的!
-
代码分析
下面是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方法,可以存储数据
1public void set(T value) { 2 //获取当前线程 3 Thread t = Thread.currentThread(); 4 //根据当前的线程获取数据 5 ThreadLocalMap map = getMap(t); 6 if (map != null) 7 map.set(this, value); 8 else 9 createMap(t, value); 10 } 11 12public T get() { 13 //获取当前线程 14 Thread t = Thread.currentThread(); 15 //根据当前的线程获取数据 16 ThreadLocalMap map = getMap(t); 17 if (map != null) { 18 //这里依据对象获取保存的数据 19 ThreadLocalMap.Entry e = map.getEntry(this); 20 if (e != null) { 21 @SuppressWarnings("unchecked") 22 T result = (T)e.value; 23 return result; 24 } 25 } 26 return setInitialValue(); 27 } 28 29 /** 30 * 这里可以看出返回的数据是当前的线程变量 31 */ 32 ThreadLocalMap getMap(Thread t) { 33 return t.threadLocals; 34 } 35 36 void createMap(Thread t, T firstValue) { 37 t.threadLocals = new ThreadLocalMap(this, firstValue); 38} 39 40 41从上面可以看出写的代码示例,返回值是不同的因为线程是独立的, 42独立线程会有自己的单独数据存储map, 43至于ThreadLocal当作key是为了防止多个ThreadLocal在同一个线程当中做区分
3. ThreadLocal做保存数据的key唯一性
1//ThreadLocal类中有一个被final修饰的类型为int的threadLocalHashCode,它在该ThreadLocal被构造的时候就会生成,相当于一个ThreadLocal的ID 2 private final int threadLocalHashCode = nextHashCode(); 3 //threadLocalHashCode值来源于这里 4 private static AtomicInteger nextHashCode =new AtomicInteger(); 5 private static final int HASH_INCREMENT = 0x61c88647; 6 private static int nextHashCode() { 7 return nextHashCode.getAndAdd(HASH_INCREMENT); 8 }