threadlocal线程
ThreadLocal
变量。 原因是他们造成了类加载器泄漏,我们不能再适当地取消部署我们的应用程序。 取消部署应用程序后,当GC根目录继续引用应用程序对象时,将发生类加载器泄漏。 如果取消部署后仍引用应用程序对象,则无法对整个类加载器进行垃圾回收,因为考虑的对象引用了您的应用程序类文件,而应用程序类文件又引用了类加载器。 取消部署和重新部署几次后,这将导致OutOfMemoryError
。 ThreadLocal
是一种经典的候选人,可以轻松在Web应用程序中创建类加载器泄漏。 服务器正在管理池中的线程。 这些线程的寿命比您的Web应用程序更长。 实际上,它们根本不会消失,直到基础JVM死亡。 现在,如果将ThreadLocal
放入引用类的对象的池线程中,则必须*小心。 您需要确保使用ThreadLocal.remove()
再次删除此变量。 Web应用程序中的问题是:安全删除ThreadLocal
变量的正确位置在哪里? 另外,您可能不想每次同事决定将另一个ThreadLocal
添加到托管线程时都修改该“删除代码”。
我们围绕线程局部开发了一个包装器类,该类将所有线程局部变量保留在一个单独的ThreadLocal
变量中。 这是代码。
public class ThreadLocalUtil {private final static ThreadLocal<ThreadVariables> THREAD_VARIABLES = new ThreadLocal<ThreadVariables>() {/*** @see java.lang.ThreadLocal#initialValue()*/@Overrideprotected ThreadVariables initialValue() {return new ThreadVariables();}};public static Object getThreadVariable(String name) {return THREAD_VARIABLES.get().get(name);}public static Object getThreadVariable(String name, InitialValue initialValue) {Object o = THREAD_VARIABLES.get().get(name);if (o == null) { THREAD_VARIABLES.get().put(name, initialValue.create());return getThreadVariable(name);} else {return o;}}public static void setThreadVariable(String name, Object value) {THREAD_VARIABLES.get().put(name, value);}public static void destroy() {THREAD_VARIABLES.remove();}
}public class ThreadVariables extends HashMap<String, Object> { }public abstract class InitialValue {public abstract Object create();}
实用程序类的优点是无需开发人员就可以单独管理线程局部变量的生命周期。 该类将所有线程局部变量放在一个变量映射中。 可以在您可以安全地删除Web应用程序中的所有线程本地变量的地方调用destroy()
方法。 在我们的例子中,这就是ServletRequestListener -> requestDestroyed()
方法。 您还需要将finally块放置在其他位置。 典型的地方是HttpServlet
的init()
, doPost()
, doGet()
方法附近。 请求完成或意外引发异常后,这可能会删除池工作线程中的所有线程本地。 有时,服务器的main
线程会泄漏线程局部变量。 如果是这种情况,则需要找到正确的位置来调用ThreadLocalUtil -> destroy()
方法。 为此,要弄清楚主线程实际上在哪里创建线程变量。 您可以使用调试器来做到这一点。
许多人建议出于多种原因而在Web应用程序中省略ThreadLocal
。 在池化线程环境中删除它们可能非常困难,因此您可以安全地取消部署应用程序。 ThreadLocal
变量可能有用,但是在应用它们之前考虑其他技术是很公平的。 Web应用程序可以携带请求范围参数的替代方法是HttpServletRequest
。 许多Web框架允许通用的请求参数访问以及请求/会话属性访问,而无需与本地Servlet / Portlet API绑定。 同样,许多框架支持请求使用依赖项注入将作用域Bean注入到对象树中。 所有这些选项都满足大多数要求,因此在使用ThreadLocal
之前应考虑这些选项。
参考:线程故事: JCG合作伙伴 Niklas的Web应用程序中的ThreadLocal。
翻译自: https://www.javacodegeeks.com/2012/05/threading-stories-threadlocal-in-web.html
threadlocal线程