问题描述,在工作中一次请求 请求接口一 ,将request保存到了ThreadLocal,调用接口二,而接口二也存入了ThreadLocal,接口二完成之后将ThreadLocal
romove 了,在此回到接口一时数据已经没有了,导致了问题.
然后就把接口二的 ThreadLocal.remove() 这行代码干掉了......
ThreadLocal 是依存于 ThreadLocalMap 的 ,key 为 Thread.currentThread();
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
在这里先说下对象的强弱软虚 容易记错的就是软和弱什么时候回收问题.
1)软引用(Soft Reference):描述的是一些还有用但非必需的对象.在系统将会发生内存溢出之前,会把这些对象列入回收范围进行二次回收,也就是说系统将会发生内存溢出了,才会对他们进行回收.
2)弱引用(Weak Reference):程度比软引用更弱一些.这些对象只能生存到下次 GC 之前.当 GC 工作时扫描到,无论内存是否足够都会将其回收.
从这里我们可以发现 k 为弱引用.v为强引用.
如果key被回收掉,则v可能发生内存泄露.
static ThreadLocal threadLocal = new ThreadLocal();
这种用法一个线程 一个线程永远只有一个KV对,并且不会被回收掉,只能是覆盖,跟随JVM启动而启动,结束而结束,可以remove删除掉自己设置的kv.
另外一种用法
class Test{
ThreadLocal threadLocal = new ThreadLocal();
}
用对象持有 Test test = new Test(); test.threadLocal.set();
如果对象使用完毕被回收(test=null; System.gc;),没有调用 threadLocal.remove();
那这个 threadLocal 没有被回收,随着GC发生K被回收掉,这时候V就永远不会被回收,即使当前线程在此赋值,就会产生一条新纪录,导致内存堆积越来越多,OOM.
JDK解决方案,当前线程 一定要在调用 get set remove 方法 会清理当前线程ThreadLocal空间内K为空的数据,赋值为NULL,帮助清理.
自己解决就是一定要按规定调用remove.