本文共 6424 字,大约阅读时间需要 21 分钟。
package com.myd.cn.ThreadLocal; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class NoThreadLocalHTTPServer { public static void main(String[] args) { simpleTest(); } public static void simpleTest(){ ExecutorService executorService = Executors.newFixedThreadPool(2); //提交线程任务 executorService.submit(()->{ Long userId = 10000L; doUserRequest(userId); }); executorService.submit(()->{ Long userId = 20000L; doUserRequest(userId); }); } private static void doUserRequest(Long userId) { ThreadContext threadContext = new ThreadContext(); threadContext.setUserId(userId); String info = getCusInfo(threadContext); Listcourses = getMyCourse(threadContext); System.out.println("user info "+info +";courses = "+courses.toString()); } private static String getCusInfo(ThreadContext threadContext){ return threadContext.getUserId() +" 的UserId信息"; } private static List getMyCourse(ThreadContext threadContext){ return Collections.singletonList(threadContext.getUserId()+" 相应的课程"); } public static class ThreadContext{ private Long userId; public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } } }
package com.myd.cn.ThreadLocal; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadLocalHTTPServer { public static void main(String[] args) { simpleTest(); } private static void simpleTest() { ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(()->{ Long userId = 1000L; doUseRequeset(userId); }); executorService.submit(()->{ Long userId = 2000L; doUseRequeset(userId); }); } private static void doUseRequeset(Long userId) { UserSessionContext.getUserSessionContext().setUserId(userId); String info = getCusInfo(); Listcourses = getCourse(); System.out.println("user info "+info +";courses = "+courses.toString()); } public static String getCusInfo(){ return UserSessionContext.getUserSessionContext().getUserId()+" 的相关信息"; } public static List getCourse(){ return Collections.singletonList(UserSessionContext.getUserSessionContext().getUserId()+"的 相关课程信息"); } private static class UserSessionContext{ private static ThreadLocal threadLocal = ThreadLocal.withInitial(UserSessionContext::new); //获取ThreadLocal包含的(线程本地存储)的变量UserSessionContext public static UserSessionContext getUserSessionContext(){ return threadLocal.get(); } /** * 删除本地存储的变量,线程执行完毕时删除,避免内存溢出 */ public static void removeContext(){ threadLocal.remove(); } private Long userId; public static ThreadLocal getThreadLocal() { return threadLocal; } public static void setThreadLocal(ThreadLocal threadLocal) { UserSessionContext.threadLocal = threadLocal; } public Long getUserId() { return userId; } public void setUserId(Long userId) { System.out.println(Thread.currentThread().getName()+ " set userId = "+userId); this.userId = userId; } } }
1.代码
package com.myd.cn.ThreadLocal;import java.lang.ref.WeakReference; /** * 测试弱引用,弱引用的对象并没有被其他对象直接引用, * 那么对于ThreadLocal->threadlocals->threadLlocalMap->key的弱引用被回收,相应强引用的value则不会被回收,造成OOM * @author dymll * */ public class WeakReferenceOfThreadLocal { public static void main(String[] args) throws Exception { testWeakReferenceNoDirectReference() ; } public static void testWeakReferenceNoDirectReference() throws Exception{ Object obj = new Object(); WeakReference
2.结果,查看被list对象引用obj仍有输出
java.lang.Object@15db9742 null ````1.代码 package com.myd.cn.ThreadLocal; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; /** * 测试弱引用,弱引用的对象并没有被其他对象直接引用, * 那么对于ThreadLocal->threadlocals->threadLlocalMap->key的弱引用被回收,相应强引用的value则不会被回收,造成OOM * @author dymll * */ public class StrongReferenceAfterWeakReference { public static void main(String[] args) throws Exception { testWeakReferenceNoDirectReference() ; } public static void testWeakReferenceNoDirectReference() throws Exception{ Object obj = new Object(); WeakReferenceweakReference = new WeakReference (obj); System.out.println(weakReference.get()); List objects = new ArrayList<>(); //若在弱引用之后又有直接引用(强引用),则及时被置空,也不会被GC objects.add(obj); obj = null; //将obj变量置空 ,触发手动GC,后续引用为空 System.gc(); System.out.println(weakReference.get()); } }
2.结果,查看被list对象引用obj仍有输出
java.lang.Object@15db9742 java.lang.Object@15db9742## ThreadLocal数据结构- 查看其源码,ThreadLocal数据存在其下Threadlocals的ThreadLocalMap,Map有Entry构成,Entry包含每个线程作为key,value是每个线程专有的数据(这里是变量) ![ThreadLocal数据结构](https://img-blog.csdnimg.cn/20200327000458779.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2R5bWtrag==,size_16,color_FFFFFF,t_70)- 每个线程都有自己的ThreadLocal ![每个线程都有自己ThreadLocal](https://img-blog.csdnimg.cn/20200327000515974.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2R5bWtrag==,size_16,color_FFFFFF,t_70)## ThreadLocal OOM问题- key是软引用,被置空后会被回收,那么Thread->ThreadLocalMap->Entry->Value这个链路是强引用链路,ThreadLocalMap无法再通过key来访问value,value在这里不会被回收,当这样的对象过多占用内存是,发生OOM ![强引用且无法进行回收,而不能进行内存释放,造成内存泄漏](https://img-blog.csdnimg.cn/20200327000544676.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2R5bWtrag==,size_16,color_FFFFFF,t_70)- 如果解决ThreadLocal OOM问题- 在使用ThreadLocal 时,都要在线程全部指向完毕后,在finally代码块中调用remove()方法,清除内存(线程池中尤为注意要清除内存,更易因为强引用无法回收内存,造成OOM)- 保存在ThreadLocal的数据不能过大
转载地址:http://ihjzb.baihongyu.com/