1、什么是ThreadLocal
ThreadLocal用于设置当前线程的特有变量,即它里面设置的变量仅在当前线程中有效
在单线程环境下,ThreadLocal中设置的变量可以看成是一个普通变量,而在多线程环境下,即使线程A和线程B操作同一个ThreadLocal,他们获取的值也不一定相同(线程A往threadLocal中添加的变量线程B获取不到)
2、常用方法
threadLocal.set(Object object):向ThreadLocal实例中添加一个变量
threadLocal.get():获取当前ThreadLocal实例中的变量
单线程环境下执行ThreadLocal的set和get方法:
ThreadLocal<Object> local = new ThreadLocal<>();
local.set("张三"); //往ThreadLocal实例中存值
System.out.println(local.get()); //获取当前ThreadLocal中的值
运行结果:控制台中打印 "张三"
多线程环境下执行ThreadLocal的set和get方法
//获取threadlocal本地线程对象
ThreadLocal<Object> threadLocal = new ThreadLocal<>();
//往本地线程中设置变量
threadLocal.set(new Object());
new Thread() { //匿名内部类方式创建一个新的线程对象
public void run() {
System.out.println(threadLocal.get());
}
}.start(); //启动线程
Thread.sleep(1000); //确保子线程先执行
System.out.println(threadLocal.get());
运行结果:控制台打印null(这是子线程中打印的),紧接着打印一个Object对象(这是主线程即main方法所在的线程打印的)。
由此可知,对于同一个threadLocal对象,主线程中设置的变量,子线程是获取不到的。
3、原因(关于ThreadLocal的get方法和set方法源码解析)
set方法:
源码
public void set(T value) {
Thread t = Thread.currentThread(); //获取当前线程
ThreadLocalMap map = getMap(t); //通过当前线程去获取一个map集合
if (map != null) //如果map!=null,则直接往map中添值
map.set(this, value);
else
createMap(t, value); //如果map==null,则创建一个当前线程的map集合
}
//getMap方法
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
//createMap方法
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocal实例的set方法本质上其实就是往一个map集合中添加数据,
map集合中的key是当前ThreadLocal的实例对象,value是该实例对象中存储的变量。
get方法:
源码:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); //获取当前线程的map集合
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //获取map中的一项元素
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value; //获取entry中的value
return result;
}
}
return setInitialValue();
}
get方法就是获取当前线程的map集合,然后从map集合中去获取当前threadLocal对象对应的entry,根据entry去获取value
总结:
ThreadLocal的set和get方法实际上都是通过去获取线程对象(Thread对象)中维护的一个map集合进行操作的,由于不同线程对象中的map集合不相同,所以ThreadLocal设置的变量仅在当前线程中可见,在其他线程中的获取不到的
而在单线程环境下,ThreadLocal对象的获取的map集合是同一个,所以可以看成是一个普通变量