这里使用的servlet容器是 tomcat

如果在web项目中,使用 ThreadLocal 不当,会造成 OutOfMemoryError。纠正,ThreadLocal 中的引用是软引用,只有当JVM GC 后发现内存还是不够,才会回收软引用。

说明原因前
1:先讲一下 ThreadLocal,Thead,ThreadLocalMap 三者之间的一个关系。(大家可以去看一下ThreadLocal的实现源码,可而参考我的另一篇文章点击查看
ThreadLocalMap 是 ThreadLocal 的一个内部类,一看是Map,保存数据的形式就是key value 形式的。
Thread类有一个成员变量 threadLocals,这个变量的数据类型是 ThreadLocal.ThreadLocalMap。threadLocals保存数据的key是ThreadLocal本身

2:tomcat线程池
tomcat启动的时候会创建一个线程池,配置如下

<Connector port="80" protocol="HTTP/1.1" maxThreads="600" minSpareThreads="100" maxSpareThreads="500" acceptCount="700"
connectionTimeout="20000" redirectPort="8443" />

maxThreads=“600” ///最大线程数
minSpareThreads=“100”///初始化时创建的线程数
maxSpareThreads=“500”///一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。
acceptCount=“700”//指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理

这里说一下为什么 如果在web项目中,使用 ThreadLocal 不当,会造成 OutOfMemoryError。
如果调用 ThreadLocal 的 set 方法 将一个对象放入Thread中的成员变量threadLocals 中,那么这个对象是永远不会被回收的,因为这个对象永远都被Thread中的成员变量threadLocals引用这。

如果想让垃圾收集器回收它,有两种方法
1:将该线程从tomcat线程池中去除,当一个线程被回收的时候何况它的成员变量呢,但是tomcat启动一般都会配置一个线程池进行优化,所有该方法不太现实。
2:调用 ThreadLocal 的 remove 方法 将对象从hread中的成员变量threadLocals 中删除掉。

设想如果将一个大对象放入threadLocals 中,并且还没有remove。那么就可能会造成OutOfMemoryError,如果不会造成OutOfMemoryError那么也很浪费java堆内存

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐