把对象封装到一个线程里,只有一个线程能够看到该对象,那么就算这个对象不是线程安全的,也不会出现任何线程问题,由于它只能在一个线程中被访问。
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
方法。app
将ThreadLocal变量定义成private static的,这样的话ThreadLocal的生命周期就更长,因为一直存在ThreadLocal的强引用,因此ThreadLocal也就不会被回收,也就能保证任什么时候候都能根据ThreadLocal的弱引用访问到Entry的value值,而后remove它,防止内存泄露。ide
在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
中获取就能够了。工具
【关注微信公众号:【入门小站】解锁更多知识点】this