ThreadLocal为每一个使用该变量的线程提供一个变量副本,每个线程可以独立操作变量副本而不会对其他线程产生干扰和冲突,在线程中使用ThreadLocal得到变量副本来使用。这样多个线程就不会因为竞争使用一个变量而被阻塞影响性能!这样就隔离了多个线程对数据的数据共享!但是ThreadLocal是耗费内存来提高性能的!
ThreadLocal为每个线程保存了变量的副本,这样每个线程在使用变量时都使用自己的线程变量,而不会竞争但不是为了处理线程冲突,是为了在多线程环境下能够保证各个线程里的变量相对独立于其他线程内的变量!所以ThreadLocal并不是解决线程安全和同步而产生的!只是为了解决多线程竞争使用同一对象而解决的,为每个线程分配了一个副本各自使用而不影响!
1,当我们把变量放到ThreadLocal中时,每个线程都可以得到这个变量的副本,保存在ThreadLocalMap中,ThreadLocalMap记录了ThreadLocal和value的对应关系,在使用时则通过ThreadLocal来使用,因为ThreadLocal内部通过Thread得到了ThreadLocalMap!
首先,我在刚开始看ThreadLocal的时候被Thread、ThreadLocal、ThreadLocalMap绕蒙了,看了好久才理清楚,他们三个的关系是:ThreadLocalMap是ThreadLocal的内部类,Thread内部有一个ThreadLocalMap,用于保存Thread使用的ThreadLocal和value的关系,是由ThreadLocalMap内部的Entry[]保存ThreadLocal和value。为什么是Entry[]呢?因为一个Thread可以使用多个ThreadLocal!
ThreadLocal的set方法:通过Thread得到ThreadLocalMap,然后将ThreadLocal自身和value封装成Entry保存到ThreadLocalMap中,相当于Thread有了value的副本!这样,不同的ThreadLocal就可以将自身和value保存到ThreadLocalMap中,然后通过ThreadLocal去获取!
而ThreadLocal的get方法:通过得到当前Thread,拿到ThreadLocalMap,再通过ThreadLocal自身去取得value,这样就得到了变量的拷贝,这样就可以使用了!
public class TestThreadLocal { // 覆盖ThreadLocal的initialValue()方法,指定初始值 private static ThreadLocal<Integer> tl = new ThreadLocal<Integer>() { public Integer initialValue() { return 0; } }; public void printTl(){ tl.set(tl.get()+1); System.out.println(Thread.currentThread().getName() + " value: " + tl.get()); } public static void main(String[] args){ TestThreadLocal n = new TestThreadLocal(); ThreadDemo td1 = new ThreadDemo(n); ThreadDemo td2 = new ThreadDemo(n); ThreadDemo td3 = new ThreadDemo(n); Thread t1 = new Thread(td1); Thread t2 = new Thread(td2); Thread t3 = new Thread(td3); t1.start(); t2.start(); t3.start(); } } class ThreadDemo implements Runnable{ private TestThreadLocal n; public ThreadDemo(TestThreadLocal n){ this.n = n; } @Override public void run() { for(int i=0; i<3; i++){ n.printTl(); } } }
2,还可以通过ThreadLocal进行线程内数据的传递:
public class TestThreadLocal2 { private static ThreadLocal<Long> tl = new ThreadLocal<Long>(); public static void main(String[] args) throws InterruptedException { TestThreadLocal2 t2 = new TestThreadLocal2(); t2.method1(); t2.method2(); } public void method1() throws InterruptedException { long time1 = System.currentTimeMillis(); tl.set(time1); Thread.sleep(1000); } public void method2(){ long time2 = System.currentTimeMillis(); System.out.println("总共运行时间:" + (time2-tl.get())); } }