ThreadLocal是什么
在多线程环境下,防止自己的变量被其它线程篡改,实现单个线程的共享变量,ThreadLocal解决的就是每个线程绑定自己的变量值。
ThreadLocal源码解析
set()方法:
public void set(T value) {
//取到当前的单独的线程
Thread t = Thread.currentThread();
//拿到t线程的threadLocals,每个线程都有一个ThreadLocalMap
ThreadLocalMap map = getMap(t);
//每个线程的ThreadLocalMap默认为null
if (map != null)
//this指当前创建的ThreadLocal对象
map.set(this, value);
else
createMap(t, value);
}
get()方法:
public T get() {
Thread t = Thread.currentThread();
//取到单独的线程的ThreadLocalMap,一个线程有独一无二的一个Map--ThreadLocalMap
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对象,当执行set方法时,ThreadLocal对象获取到当前线程下ThreadLocalMap对象,
进行set操作,key为当前new出来的ThreadLocal对象,value为自定义的值,
存储数据的ThreadLocalMap对象保存在当前线程的threadLocals变量中,当执行set方法中,是从当前线程的threadLocals变量获取。
所以在线程1中set的值,对线程2来说是摸不到的,而且在线程2中重新set的话,也不会影响到线程1中的值,
保证了线程之间不会相互干扰。
ThreadLocal使用
public static void main(String[] args) {
//当前main线程下,new多个ThreadLocal对象,其实是向main线程的成员变量:
//ThreadLocal.ThreadLocalMap threadLocals中set多个值,key分别为:
//threadLocal1,threadLocal2
ThreadLocal threadLocal1 = new ThreadLocal();
threadLocal.set("ceshi1");
ThreadLocal threadLocal2 = new ThreadLocal();
threadLocal1.set("ceshi2");
System.out.println(threadLocal1.get());
System.out.println(threadLocal2.get());
}
结果输出:ceshi1
ceshi2
ThreadLocal内存泄露
//threadLocalMap存储的entry对象,是WeakReference弱引用
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
因为threadLocalMap,中的enrty对象key是弱引用(只要gc,不管内存是否充足必定会回收
,而map的value是强引用不会回收,存在内存泄露问题)
ThreadLocal内存泄露解决
try {
//业务逻辑
} finally {
//remove实际调用Thread线程中threadLocalMap的remove方法,删除掉不用的key,value,
//threadLocalMap依然在.
threadLocal对象.remove();
}
FastThreadLocal是ThreadLocal替代品,吞吐量更高,速度更快
InheritableThreadLocal关键字
InheritableThreadLocal关键字中子线程会继承父线程存储的数据。子线程可以修改继承的主线程的存储数据,且主线程的存储数据不受影响。
public class Test {
public static InheritableThreadLocal threadLocal = new InheritableThreadLocal();
public static void main(String[] args) throws Exception{
threadLocal.set("主线程的值");
System.out.println(threadLocal.get());
Thread.sleep(3000);
new Thread( ()-> {
threadLocal.set("子线程的值");
System.out.println(threadLocal.get());
}).start();
Thread.sleep(3000);
System.out.println(threadLocal.get());
}
}
运行结果