ThreadLocal应用及理解
转载请注明出处:
1. 先展示threadLocal的一个简单封装,该封装用来在不同的请求线程中解析用户参数。在请求经过过滤器时,
对用户的信息进行设置入 ThreadLocalContext 中,可在同一个请求的不同业务中获取用户的信息参数。
import com.homepage.UserInfo; public class ThreadLocalContext { private static ThreadLocal<UserInfo> userThreadLocal = new ThreadLocal<>(); public static UserInfo getThreadLocalContext(){ UserInfo user = userThreadLocal.get(); if (user == null){ return new UserInfo(); } return user; } public static void setUserThreadLocal(UserInfo user){ userThreadLocal.set(user); } public static void clear(){ userThreadLocal.remove(); } }
以上为ThreadLocal的一个简单封装。
2. 使用的场景主要为:
- 每个线程需要有自己单独的实例
- 实例需要在多个方法中共享,但不希望被多线程共享
3.原理:
每个运行的线程都会有一个类型为ThreadLocal.ThreadLocalMap的map,这个map就是用来存储与这个线程绑定的变量,
map的key就是ThreadLocal对象,value就是线程正在执行的任务中的某个变量的包装类Entry。可以通过set方法来看threadLocal实现的原理:
/** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of * this thread-local. */ public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
4.ThreadLocal作用:
在多线程程序中,同一个线程在某个时间段只能处理一个任务.我们希望在这个时间段内,任务的某些变量能够和处理它的线程进行绑定,
在任务需要使用这个变量的时候,这个变量能够方便的从线程中取出来.ThreadLocal能很好的满足这个需求,用ThreadLocal变量的程序看起来
也会简洁很多,因为减少了变量在程序中的传递。
5. 为什么ThreadLocalMap的Entry是一个weakReference?
使用weakReference,能够在ThreadLocal失去强引用的时候,ThreadLocal对应的Entry能够在下次gc时被回收,回收后的空间能够得到复用,
在一定程度下能够避免内存泄露.
6. 使用ThreadLocal应该注意什么?
在使用ThreadLocal对象,尽量使用static,不然会使线程的ThreadLocalMap产生太多Entry,从而造成内存泄露
7.使用threadLocal 如何避免内存泄露:
在 threadLocal 中的变量在线程结束之前清空 当前 threadLocal 中的变量。或是在threadLocal中变量使用结束时,手动清除 threadLocal 的变量
可以调用上面中的
ThreadLocalContext.clear() 方法或
ThreadLocalContext.set(null);