Jim*_*Jim 19 java multithreading thread-local
当ThreadLocal我使用时应该总是remove()在我完成时或当我这样做时set,旧的值被替换,因此remove是多余的?
Ami*_*nde 16
由于ThreadLocal拥有Map的currentThread和value,现在,如果你不删除其使用它,然后它会创建一个内存泄漏线程的值.
您应该始终调用remove,因为ThreadLocal类放置ThreadLocal.Values localValues定义的Thread类中的 值; 这也将导致保持Thread和相关对象的引用.
来自的源代码 ThreadLocal
该值将设置为null,并且基础条目仍将存在.
Pet*_*rey 15
set 总是替换旧值.
这是真的
你的意思是没有删除它不会被GCed?
在线程死亡之前不会删除它.没有你调用remove()它就不会消失在你身上
这是否是内存泄漏取决于您的程序.您将不得不使用大型线程本地对象创建大量线程,而这些线程由于某些原因而不需要.例如,1000个带有1 KB对象的线程可能浪费高达1 MB,但如果您正在做这类事情,这表明存在设计问题.
你可能会遇到内存泄漏的唯一地方是.
for (int i = 0; ; i++) {
// don't subclass Thread.
new Thread() {
// this is somewhat pointless as you are defining a ThreadLocal per thread.
final ThreadLocal<Object> tlObject = new ThreadLocal<Object>() {
};
public void run() {
tlObject.set(new byte[8 * 1024 * 1024]);
}
}.start();
Thread.sleep(1);
if (i % 1000 == 0) {
System.gc();
System.out.println(i);
}
}
Run Code Online (Sandbox Code Playgroud)
-verbosegc印有图案.
[Full GC 213548K->49484K(3832192K), 0.0334194 secs]
39000
[GC 2786060K->82412K(3836864K), 0.0132035 secs]
[GC 2815569K->107052K(3836544K), 0.0212252 secs]
[GC 2836162K->131628K(3837824K), 0.0199268 secs]
[GC 2867613K->156204K(3837568K), 0.0209828 secs]
[GC 2886894K->180780K(3838272K), 0.0191244 secs]
[GC 2911942K->205356K(3838080K), 0.0187482 secs]
[GC 421535K->229932K(3838208K), 0.0192605 secs]
[Full GC 229932K->49484K(3838208K), 0.0344509 secs]
40000
Run Code Online (Sandbox Code Playgroud)
注意:完整GC后的大小是相同的 49484K
在上面的例子中,你将有一个ThreadLocal,它引用引用ThreadLocal的Thread.但是,由于线程已死,因此它不会导致内存泄漏,因为它成为一个关注对象,即当A - > B和B - > A时
我在循环中运行上面的例子几分钟,GC水平移动了很多,但最小尺寸仍然很小.
不,不需要每次都调用remove()而不是set()
如果您担心内存泄漏,请参阅javadoc的内容
只要线程处于活动状态并且 ThreadLocal 实例可访问,每个线程就持有对其线程局部变量副本的隐式引用;线程消失后,其线程本地实例的所有副本都将受到垃圾回收(除非存在对这些副本的其他引用)。
因此,不调用remove()不会阻止线程本地实例被正确的垃圾收集,并且本质上不会导致任何内存泄漏。
您还可以查看 ThreadLocal 实现,它使用WeakReferences来实现这种“隐式引用”机制
但要注意与线程池的一致性
仅将set()方法与线程池一起使用,您可能更喜欢remove() ThreadLocal 实例,而不是使用同一线程在另一个“工作单元”中覆盖它。因为您可能希望避免由于某种原因未调用 set 方法,并且您的 ThreadLocal 仍然附加到它不属于的上下文/处理的情况。