把对象封装到一个线程里,只有一个线程可以看到该对象,那么就算这个对象不是线程安全的,也不会出现任何线程问题,因为它只能在一个线程中被访问。
ThreadLocal
类来实现线程封闭,这个类使线程中的某个值与保存值的对象关联起来核心的五个操作:创建,创建并赋初始值,赋值,取值,删除
private final static ThreadLocal<Object> threadLocal = new ThreadLocal<Object>;
private final static ThreadLocal<String> threadLocal=new ThreadLocal<String>(){
@Override
protected String initialValue() {
return "入门小站";
}
};
threadLocal.set("入门小站");
threadLocal.get();
threadLocal.remove();
首先
ThreadLocal
是一个泛型类,保证可以接受任何类型的对象。一个线程内可以存在多个
ThreadLocal
,ThreadLocal
内部维护了一个Map
,这个Map
不是HashMap
,而是ThreadLocal
实现的一个ThreadLocalMap
的静态内部类。我们使用的get()
,set()
方法其实是调用了这个ThreadLocalMap
类对应的get()
,set()
。
public T get() {
Thread t = Thread.currentThread();
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();
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
调用
ThreadLocal
的set方法时,先获取当前的线程Thread t = Thread.currentThread();
,然后获取当前线程维护的ThreadLocalMap
。如果ThreadLocalMap
不存在则初始化。
ThreadLocalMap
的map.set(this, value);
第一个参数是this
,this
指的是当前的ThreadLocal
,就是上面代码里面的threadLocal
变量。最终的变量是放在当前线程的
ThreadLocalMap
中,并不是存在ThreadLocal
上,ThreadLocal
可以理解成传递关系的。
ThreadLocalMap
中使用的key
为ThreadLocal
的弱引用,弱引用的特点是,如果这个对象只存在弱引用,那么在下一次垃圾回收的时候必然会被清理掉。所以
ThreadLocal
没有被强引用的情况下,在垃圾回收的时候会被清理掉,但是value
却是强引用,不会被清理,这样的话就出出现key
为null
的value
。
ThreadLocalMap
实现中已经考虑了这个情况,在调用set
,get
,remove
方法的时候会清理掉key
为null
的记录。如果出现了内存泄漏,那就是说在key
为null
后,没有手动调用remove
方法,并且之后也不再调用set
,get
,remove
方法。
将ThreadLocal变量定义成private static的,这样的话ThreadLocal的生命周期就更长,由于一直存在ThreadLocal的强引用,所以ThreadLocal也就不会被回收,也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值,然后remove它,防止内存泄露。
在ThreadLocal类中,还包含了一个static修饰的AtomicInteger(əˈtɒmɪk提供原子操作的Integer类)成员变量(即类变量)和一个static final 修饰的常量(作为两个相邻nextHashCode的差值)。由于nextHashCode是类变量,所以每一次调用ThreadLocal类都可以保证nextHashCode被更新到新的值,并且下一次调用ThreadLocal类这个被更新的值仍然可用,同时AtomicInteger保证了nextHashCode自增的原子性。
ThreadLocal
应用
Web
项目公共参数从controller层传递到service层,再从service层传递到mapper层,或者从service层传递到其他的工具类当中。为了避免参数复杂的传递,在controller中将已经封装好的参数放入ThreadLocal中,在其他层调用时直接通过ThreadLocal对象获取。在方法结束时,定义拦截器(HandlerInterceptorAdapter)(或者Filter)进行ThreadLocal的remove方法。
在需要登录的系统中用户信息常常存在
Session
和token
。比如我们要从Session
中获取用户信息需要在接口参数中加上HttpServletRequest对象,然后调用 getSession方法,且每一个需要用户信息的接口都要加上这个参数,才能获取Session,比较麻烦。这个时候我们就可以用
ThreadLocal
,在拦截器(HandlerInterceptorAdapter)(或者Filter)中解析获取用户信息,然后保存到ThreadLocal
,业务逻辑直接在ThreadLocal
中获取就可以了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。