自定义 ThreadLocal 类 的 ThreadLocal 泄漏说明

Explanation of ThreadLocal leaks for custom ThreadLocal classes

我一直在阅读 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)泄漏的解释,我不明白:

If the LeakingServlet is invoked at least once and the Thread that served it is not stopped, then we created a classloader leak !

The leak is caused because we have a custom class for the ThreadLocal instance, and also a custom class for the value bound to the Thread. Actually the important thing is that both classes were loaded by the webapp classloader.

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

解释不正确:

The leak is caused because we have a custom class for the ThreadLocal instance

那部分是错误的。 Thread class 中的 ThreadLocalMap 使用 weakReferences 作为键,因此 threadLocal 实例是否是自定义实例并不重要 class。我用我的自定义 ThreadLocal class 测试了它,没有内存泄漏。

, and also a custom class for the value bound to the Thread.

这是正确的。对于值线程不使用弱引用,因此如果值是自定义 class 将阻止它的 class 加载程序被垃圾收集,这将导致所有 class 由该 [=18] 加载=] 加载程序保留在内存中,直到线程从线程池中删除。