使用 ThreadLocal 的目的在与实现线程内的数据共享。
每个线程调用 ThreadLocal 对象的set方法,就相当于往其内部的map中添加一条记录,key是各自的线程对象,value是各自的set方法传进去的值。在线程结束时可以调用ThreadLocal.clear()方法进行释放内存。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal
如下列代码
public class Test {
static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()+"数据:"+data);
x.set(data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get() {
int data = x.get();
System.out.println("A from"+Thread.currentThread().getName()+"数据:"+data);
}
}
static class B{
public void get() {
int data = x.get();
System.out.println("B from"+Thread.currentThread().getName()+"数据:"+data);
}
}
执行结果:
可以看到ThreadLocal 保证了每个线程数据的正确性。我们再进入ThreadLocal 的源码看一下。
在执行 map.set(this,value)时完成与线程对象的绑定。
而在执行put时由 map.getEntry(this) 得到绑定的线程对象。
可以看到每个线程中都有一个ThreadLocalMap数据结构,进入查看
当执行set方法时,其值是保存在当前线程的threadLocals变量中,当执行set方法中,是从当前线程的threadLocals变量获取。所以在线程A中set的值,对线程B来说获取不到,而且在线程B中重新set的话,也不会影响到线程A中的值,保证了线程之间不会相互干扰。