【问题标题】:Explanation of ThreadLocal leaks for custom ThreadLocal classes自定义 ThreadLocal 类的 ThreadLocal 泄漏说明
【发布时间】:2017-12-20 12:32:30
【问题描述】:

我一直在阅读这个article 关于 Tomcat 中的 ThreadLocal 泄漏。第一个示例包含以下代码:

public class MyCounter {
        private int count = 0;

        public void increment() {
                count++;
        }

        public int getCount() {
                return count;
        }
}

public class MyThreadLocal extends ThreadLocal<MyCounter> {
}

public class LeakingServlet extends HttpServlet {
        private static MyThreadLocal myThreadLocal = new MyThreadLocal();

        protected void doGet(HttpServletRequest request,
                        HttpServletResponse response) throws ServletException, IOException {

                MyCounter counter = myThreadLocal.get();
                if (counter == null) {
                        counter = new MyCounter();
                        myThreadLocal.set(counter);
                }

                response.getWriter().println(
                                "The current thread served this servlet " + counter.getCount()
                                                + " times");
                counter.increment();
        }
}

它说所有的类都驻留在 webapp 中。然后它概述了类加载器(不是 ThreadLocal)泄漏的以下解释,我不明白:

如果 LeakingServlet 至少被调用一次并且线程 服务它没有停止,然后我们创建了一个类加载器泄漏!

泄漏是因为我们有一个 ThreadLocal 的自定义类 实例,以及绑定到 Thread 的值的自定义类。 实际上重要的是这两个类都是由 webapp 类加载器。

ThreadLocal 泄漏的解释很糟糕。如果服务请求的线程没有停止,我们怎么会有 ThreadLocal 泄漏(实际上文章说是类加载器泄漏)?这是否意味着,如果 Thread 是 Tomcat 线程池的一部分,并且由于 MyThreadLocal.remove() 尚未关闭,那么 MyCounter / MyThreadLocal 的 webapp 类加载器不能被垃圾收集,因为 Thread 返回到池中?打电话MyThreadLocal.remove() 会解决这个问题吗?我不明白。

【问题讨论】:

    标签: java tomcat thread-local


    【解决方案1】:

    解释不正确:

    泄漏是因为我们有一个 ThreadLocal 实例的自定义类

    那部分是错误的。 Thread 类中的 ThreadLocalMap 使用弱引用作为键,因此 threadLocal 实例是否是自定义类无关紧要。我用我的自定义 ThreadLocal 类对其进行了测试,没有内存泄漏。

    ,也是绑定到 Thread 的值的自定义类。

    这是正确的。对于值线程不使用弱引用,因此如果一个值是一个自定义类,它将阻止它的类加载器被垃圾收集,这将导致该类加载器加载的所有类都留在内存中,直到线程从线程池中删除。

    【讨论】:

    • 但是你什么时候会打电话?它只会从当前线程中清除 ThreadLocal。最好使用 AtomicLong 而不是自定义类,这样您就不会出现类加载器泄漏,因为 AtomicLong 是由引导类加载器加载的,而不是由加载应用程序的同一个类加载器加载的。
    • 另一个解决方案是使用我创建的 ImprovementThreadLocal。在github上找到它。
    猜你喜欢
    • 2011-11-25
    • 2013-07-31
    • 2011-12-16
    • 2015-12-28
    • 2022-06-10
    • 2010-10-30
    • 1970-01-01
    • 2014-07-30
    • 1970-01-01
    相关资源
    最近更新 更多