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();}
實用程序類的優點是無需開發人員就可以單獨管理線程局部變量的生命周期。 該類將所有線程局部變量放在一個變量映射中。 可以調用destroy()
方法,在其中可以安全地刪除Web應用程序中的所有線程本機。 在我們的例子中,這就是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