Threadlocal删除?

Jim*_*Jim 19 java multithreading thread-local

ThreadLocal我使用时应该总是remove()在我完成时或当我这样做时set,旧的值被替换,因此remove是多余的?

Ami*_*nde 16

由于ThreadLocal拥有MapcurrentThreadvalue,现在,如果你不删除其使用它,然后它会创建一个内存泄漏线程的值.

您应该始终调用remove,因为ThreadLocal类放置ThreadLocal.Values localValues定义的Thread类中的 值; 这也将导致保持Thread和相关对象的引用.

来自的源代码 ThreadLocal

该值将设置为null,并且基础条目仍将存在.


Pet*_*rey 15

set 总是替换旧值.

这是真的

  • Calendar.set()和Date.set()
  • BitSet.set()
  • List.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水平移动了很多,但最小尺寸仍然很小.


Rém*_*tos 9

,不需要每次都调用remove()而不是set()

如果您担心内存泄漏,请参阅javadoc的内容

只要线程处于活动状态并且 ThreadLocal 实例可访问,每个线程就持有对其线程局部变量副本的隐式引用;线程消失后,其线程本地实例的所有副本都将受到垃圾回收(除非存在对这些副本的其他引用)。

因此,不调用remove()不会阻止线程本地实例被正确的垃圾收集,并且本质上不会导致任何内存泄漏。

您还可以查看 ThreadLocal 实现,它使用Wea​​kReferences来实现这种“隐式引用”机制

要注意与线程池的一致性

仅将set()方法与线程池一起使用,您可能更喜欢remove() ThreadLocal 实例,而不是使用同一线程在另一个“工作单元”中覆盖它。因为您可能希望避免由于某种原因未调用 set 方法,并且您的 ThreadLocal 仍然附加到它不属于的上下文/处理的情况。