Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/390.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java线程池中是否对ThreadLocal值进行GCed?_Java_Multithreading_Garbage Collection_Threadpoolexecutor_Thread Local - Fatal编程技术网

在Java线程池中是否对ThreadLocal值进行GCed?

在Java线程池中是否对ThreadLocal值进行GCed?,java,multithreading,garbage-collection,threadpoolexecutor,thread-local,Java,Multithreading,Garbage Collection,Threadpoolexecutor,Thread Local,在我的代码中,我想测试ThreadLocal的GC策略。我使用两种方法。一个是ThreadPool,另一个是自行创建的线程。在第一个场景中,JVM没有像GC线程的ThreadLocalMap那样(没有finalize()输出)。另一个效果很好 我找到了。2007年10月,Josh Bloch(java.lang.ThreadLocal与Doug Lea的合著者)写道: “线程池的使用需要非常小心。线程池的草率使用 池与随意使用线程局部变量相结合可能导致 在许多地方都注意到了意外的对象保留。” 我

在我的代码中,我想测试ThreadLocal的GC策略。我使用两种方法。一个是
ThreadPool
,另一个是自行创建的线程。在第一个场景中,
JVM
没有像GC线程的
ThreadLocalMap
那样(没有
finalize()
输出)。另一个效果很好

我找到了。2007年10月,Josh Bloch(java.lang.ThreadLocal与Doug Lea的合著者)写道:

“线程池的使用需要非常小心。线程池的草率使用 池与随意使用线程局部变量相结合可能导致 在许多地方都注意到了意外的对象保留。”

我猜
ThreadPool
使用
ThreadLocal
可能很危险

这是我的代码(JDK8环境)

此版本的
main()
运行良好,将打印来自
finalize()
方法的所有收集消息


最后,当
Entry
的键的实例没有稳定的引用时,javagc可能不会收集值。由于
ThreadLocalMap
的键是弱引用,
Entry
的键变为
null
。但是,
条目
的值不是GCed。这个结论可以在我的测试中得到证实。

线程本地本身的实例仅仅是存储在线程本身上的映射的视图。正在收集的实例实际上并不保证引用被切断

它可以近似为
threadInstance.privateField=WeakHashMap

这意味着如果
线程
实例变得不可访问,那么将成为
线程本地
持有的所有关联值。另一方面,当
ThreadLocal
实例变得不可访问时,这只意味着映射键为空(为弱引用),该值仍由映射保持活动状态,直到对映射的某些访问清除该值。映射清除是惰性执行的,因此清理
ThreadLocal
引用与让线程终止的效果不同。 清理它的第三种方法是从线程内调用
threadLocal.remove()


当然,在一个类中共享
静态final ThreadLocal tl
访问器是一种常见的模式。当与线程池结合使用时,这意味着这些值将与线程池一样保持活动状态,除非您使用
remove()

ThreadLocal
本身的实例仅是存储在线程本身上的映射的视图。正在收集的实例实际上并不保证引用被切断

它可以近似为
threadInstance.privateField=WeakHashMap

这意味着如果
线程
实例变得不可访问,那么将成为
线程本地
持有的所有关联值。另一方面,当
ThreadLocal
实例变得不可访问时,这只意味着映射键为空(为弱引用),该值仍由映射保持活动状态,直到对映射的某些访问清除该值。映射清除是惰性执行的,因此清理
ThreadLocal
引用与让线程终止的效果不同。 清理它的第三种方法是从线程内调用
threadLocal.remove()

当然,在一个类中共享
静态final ThreadLocal tl
访问器是一种常见的模式。当与线程池结合使用时,这意味着这些值将与线程池一样保持活动状态,除非您使用
remove()

我猜ThreadPool使用ThreadLocal可能很危险

我不会走这么远。我想说,您需要考虑到,除非线程本身终止,否则不会获取
ThreadLocal
存储

但是,在查看测试代码时,
ExecutorService
和directthreadmain方法都存在很多问题。在这两种情况下,您都没有正确地连接已完成的线程。在调用
gc()
之前,放弃倒计时闩锁,并执行以下操作:

for (int i = 0; i < 10; i++) {
    all[i].join();
}
但代码的真正问题是,终结器线程存在竞争条件。gc线程完成,但对象的实际终结发生在gc完成后的另一个“终结器”线程中。如果您在
main()
的末尾只睡1秒钟,您应该会看到所有10个SDF都被捕获

这实际上表明,很难以这种方式将对象强制到GC'd。将
System.out.println(…)
命令放入
finalizer()
会让我觉得很冷,即使我知道您这样做是为了了解
ThreadLocal
的内存使用情况

我认为在
ThreadLocal
s中存储东西,如果操作小心,应该不会有问题。在线程的run方法中,我只需执行一个
try/finally
块,并确保在
finally
中执行
threadLocal.remove()
,以便线程在退出之前自行清理。但是,如果我有一个后台线程在我的应用程序的生命周期中运行,我甚至不会为此烦恼。实际上,你需要特别担心的只是来来往往的线程

最后,不需要将
ThreadLocal
字段设置为
volatile
,如果可能的话,它应该是
ParseDate
中的
static

希望这有帮助

我猜ThreadPool使用ThreadLocal可能很危险

我不会走这么远。我想说,您需要考虑到,除非线程本身终止,否则不会获取
ThreadLocal
存储

但是,在查看测试代码时,
ExecutorService
和directthreadmain方法都存在很多问题。在这两种情况下,你都没有正确地加入
// code with ThreadPool
    public static void main(String[] args) throws InterruptedException {
        ExecutorService es = Executors.newFixedThreadPool(10);

        for(int i = 0; i < 10; i++){
            es.execute(new ParseDate(i));
        }
        cd.await();

        es.shutdown();
        es.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
        System.gc();

    }
for (int i = 0; i < 10; i++) {
    all[i].join();
}
es.shutdown();
es.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);