网站上怎么做弹目提醒,陕西省建设信息管理网站,vue vs wordpress,网络营销的概念是谁提出来的首先#xff0c;看一张整体的结构图#xff0c;来帮助理解
什么是ThreadLocal
ThreadLocal用于创建线程局部变量#xff0c;如果创建一个ThreadLocal变量#xff0c;那么访问这个变量的每个线程都会有这个变量的一个副本#xff0c;在实际多线程操作的时候#xff0c;…首先看一张整体的结构图来帮助理解
什么是ThreadLocal
ThreadLocal用于创建线程局部变量如果创建一个ThreadLocal变量那么访问这个变量的每个线程都会有这个变量的一个副本在实际多线程操作的时候操作的是自己本地内存中的变量从而规避了线程安全问题
ThreadLocal的简单使用
package test;public class ThreadLocalTest {static ThreadLocalString threadLocal new ThreadLocal();public static void main(String[] args) {Thread t1 new Thread(()-{//设置线程1的本地变量的值threadLocal.set(线程1);System.out.println(threadLocal.get());threadLocal.remove();System.out.println(after remove : threadLocal.get());});Thread t2 new Thread(()-{//设置线程2的本地变量threadLocal.set(线程2);System.out.println(threadLocal.get());threadLocal.remove();System.out.println(after remove : threadLocal.get());});t1.start();t2.start();}
}输出结果 由此可知虽然threadLocal为成员变量即线程共享但使用threadLocal在不用线程进行赋值、获取等操作时不同线程的操作互不相扰。 那么ThreadLocal是如何作为成员变量却能在实现多线程下数据不共享作为线程局部变量
ThreadLocal的原理
回到一开始的图
ThreadLocal并不实际存储数据而是作为一个工具类提供get、set方法根据当前线程用于操作当前线程中的实际数据每个Thread线程中都持有一个ThreadLocal.ThreadLocalMap类型的成员变量初始值为null。ThreadLocal的get、set方法实际上就是在操作这个成员变量。ThreadLocalMap持有一个Entry[]类型的成员变量table类似JDK1.7的HashMap中的Entry[] table 可以类比学习Entry key为ThreadLocal?类型的的弱引用value为Object类型的强引用
ThreadLocal的set()
public void set(T value) {//1、获取当前线程调用者线程Thread t Thread.currentThread();//2、获取当前线程的ThreadLocalMap变量ThreadLocalMap map getMap(t);//3、如果map不为null就直接添加本地变量key为当前定义的ThreadLocal变量的this引用值为添加的本地变量值if (map ! null)map.set(this, value);//4、如果map为null说明首次添加需要首先创建出对应的mapelsecreateMap(t, value);
}ThreadLocalMap getMap(Thread t) {//获取线程的threadLocalsreturn t.threadLocals;
}void createMap(Thread t, T firstValue) {//创建线程的threadLocals, this为ThreadLocal?的引用t.threadLocals new ThreadLocalMap(this, firstValue);
}ThreadLocal的get() 在get方法的实现中首先获取当前调用者线程如果当前线程的threadLocals不为null就直接返回当前线程绑定的本地变量值否则执行setInitialValue方法初始化threadLocals变量。在setInitialValue方法中类似于set方法的实现都是判断当前线程的threadLocals变量是否为null是则添加本地变量这个时候由于是初始化所以添加的值为null否则创建threadLocals变量同样添加的值为null。 引用自https://www.cnblogs.com/fsmly/p/11020641.html#_label0 public T get() {//1、获取当前线程Thread t Thread.currentThread();//2、获取当前线程的threadLocals变量ThreadLocalMap map getMap(t);//3、如果threadLocals变量不为null就可以在map中查找到本地变量的值if (map ! null) {ThreadLocalMap.Entry e map.getEntry(this);if (e ! null) {SuppressWarnings(unchecked)T result (T)e.value;return result;}}//4、执行到此处threadLocals为null调用该更改初始化当前线程的threadLocals变量return setInitialValue();
}private T setInitialValue() {//protected T initialValue() {return null;}T value initialValue();//获取当前线程Thread t Thread.currentThread();//以当前线程作为key值去查找对应的线程变量找到对应的mapThreadLocalMap map getMap(t);//如果map不为null就直接添加本地变量key为当前线程值为添加的本地变量值if (map ! null)map.set(this, value);//如果map为null说明首次添加需要首先创建出对应的mapelsecreateMap(t, value);return value;
}ThreadLocal操作总结
根据上述源码的分析可知ThreadLocal最终操作的都是调用线程的ThreadLocalMap成员变量因此不同线程使用同一个ThreadLocal成员变量互不相扰。 每个线程内部有一个ThreadLocal.ThreadLocalMap类型threadLocals的成员变量该变量的类型为类似于HashMap其中的key为当前定义的ThreadLocal变量的this引用value为使用set方法设置的值。每个线程的本地变量存放在自己的本地内存变量threadLocals中如果当前线程一直不消亡那么这些本地变量就会一直存在所以可能会导致内存溢出因此使用完毕需要将其remove掉。
ThreadLocal使用不当造成内存泄漏问题
弱引用
弱引用这里讨论ThreadLocalMap中的Entry类的重点如果一个对象只具有弱引用那么这个对象就会被垃圾回收器GC掉(被弱引用所引用的对象只能生存到下一次GC之前当发生GC时候无论当前内存是否足够弱引用所引用的对象都会被回收掉)。弱引用也是和一个引用队列联合使用如果弱引用的对象被垃圾回收期回收掉JVM会将这个引用加入到与之关联的引用队列中。若引用的对象可以通过弱引用的get方法得到当引用的对象呗回收掉之后再调用get方法就会返回null
ThreadLocalMap内部实际上是一个Entry数组
Entry是继承自WeakReference弱引用的一个类。Entry的key是指向ThreadLocal的弱引用value一般为强引用
当一个线程调用ThreadLocal的set方法设置变量的时候当前线程的ThreadLocalMap就会存放一个记录(Entry)这个记录的key值为ThreadLocal的弱引用value就是通过set设置的值。 如果当前线程一直存在且没有调用该ThreadLocal的remove方法此时存在两种情况
ThreadLocalMap之外存在ThreadLocal的引用那么当前线程中的ThreadLocalMap中会存在对ThreadLocal变量的引用和value对象的引用无法进行垃圾回收导致这些本地变量一直存在可能会出现内存溢出ThreadLocalMap之外不存在ThreadLocal的引用因为ThreadLocalMap中的Entry的key使用的是ThreadLocal对象的弱引用所以下一次垃圾回收时ThreadLocalkey将被回收。此时ThreadLocalMap中就可能存在key为null但是value不为null的现象出现内存泄漏。
因此每次使用完ThreadLocal建议调用它的remove()方法清除数据避免内存泄漏
内存泄漏问题总结
ThreadLocalMap中的Entry的key使用的是ThreadLocal对象的弱引用在没有其他地方对ThreadLocal存在依赖时ThreadLocalMap中的ThreadLocal对象即key就会被回收而如果其他地方存在ThreadLocal的引用则不会被回收。当key被回收时Map中就可能存在key为null但是value不为null的现象出现内存泄漏。
因此每次使用完ThreadLocal建议调用它的remove()方法清除数据避免内存泄漏。
参考
ThreadLocalJava中的ThreadLocal详解TheadLocal 引起的内存泄露故障分析