它将很好地启动。 像大多数故事一样。 您会发现一个新概念,并对其功能感到惊讶。 然后突然装备了这把新锤子,一切开始看起来像钉子。 根据我们过去几个月的经验, java.lang.ThreadLocal真是一锤定音。
我想这全都归结为ThreadLocal的工作原理。 通过范围界定类推最容易理解这个概念。 以同样的方式,您的Spring Bean可以处于容器,会话或请求范围内。 ThreadLocal使您可以在Thread范围内声明对象。
您可以将任何对象设置为ThreadLocal,并且该对象在访问该对象的线程中将具有全局作用域和局部作用域。 首先可能会很复杂,但让我解释一下:
- 线程可以全局访问ThreadLocal中存储的值。 这意味着,如果您可以访问代码中的ThreadLocal引用,则可以从该线程内部的任何位置访问其中存储的值。 如果线程从多个类调用方法,则所有方法都可以看到其他方法设置的ThreadLocal变量(因为它们在同一线程中执行)。 该值无需显式传递。 就像使用全局变量一样。
- 存储在ThreadLocal中的值是线程本地的,这意味着每个线程将拥有自己的ThreadLocal变量。 一个线程无法访问/修改其他线程的ThreadLocal变量。
因此,在这里我们有一个值得庆祝的理由–我们手中有一个真正强大的概念。 这通常是呈现有状态类线程安全的最简单方法。 并封装非线程安全类,以便可以在多线程环境中安全地使用它们。 除了简单之外,使用ThreadLocal存储每个线程单个信息或每个线程上下文信息还包含有价值的信息–通过使用ThreadLocal ,很明显,线程之间不共享存储在ThreadLocal中的对象,从而简化了任务确定类是否是线程安全的。 当您手头有1,000,000行的代码库时,我们发现这并非易事。
另一方面,这个强大的概念在错误的手中会产生许多问题。 像其他任何滥用的设计概念一样。 在过去的几个月中,我们最经常遇到两个问题:
- ThreadLocal使您可以使用变量,而无需在方法调用链中显式传递它们。 在某些情况下可能有用。 但是你们那里创建了n层体系结构以抽象出不同的通信接口的人们。 然后从您的DAO对象中的ThreadLocals中获取HttpServletRequest ……您在做这个决定时在吸烟吗? 我们在研究这个特定案例时花了几个小时和第二双眼睛。 但是无论如何-使用全球化的力量时要小心。 您最终在代码中创建了意外的依赖关系。 您可能还记得–这不是明智的选择。
- 使用ThreadLocal时,很容易在代码中引入内存泄漏。 这很好地说明了类加载器周围的复杂性。 如果要在应用程序服务器中部署代码,则将使用与应用程序服务器本身使用的类加载器不同的类加载器加载/卸载应用程序类。 这本身还不错。 但是,现在考虑到现代应用程序服务器也池化线程,而不是在每个HttpRequest上创建一个新线程,我们为问题奠定了基础。
如果其中一个应用程序类将一个值存储在ThreadLocal变量中,并且在手头的任务完成后没有将其删除,则该Object的副本将与Thread一起保留(来自应用程序服务器线程池)。 由于池化线程的寿命超过了应用程序的寿命,因此它将防止该对象,从而使ClassLoader负责加载应用程序而不会被垃圾回收。 而且我们创建了一个泄漏,有机会以一种很好的旧java.lang.OutOfMemoryError:PermGen空间形式浮出水面。
因此,考虑到它可能造成的危害,我们应该避免使用ThreadLocal吗? 约书亚·布洛赫(Joshua Bloch)十年前曾说过:
“您是否可以通过线程局部变量导致意外的对象保留? 你当然可以。 但是您也可以使用数组来执行此操作。 这并不意味着线程局部变量(或数组)是坏事。 只是您必须谨慎使用它们。 使用线程池需要格外小心。 随意使用线程池与随意使用线程本地变量相结合会导致意外的对象保留,这在许多地方都已提到。 但是,将责任归咎于线程本机是没有根据的。”
我倾向于同意布洛赫先生的观点,并且不认为ThreadLocal是邪恶的创造。 但是我也确实认为这是许多人无法正确理解的概念。
本文的灵感主要收集在寻找一些令人讨厌的错误的不眠之夜中。 但是在写作时,以下资源也被证明是有益的:
- Veera Sundar 博客文章解释了范围界定
- Javin Paul关于ThreadLocal泄漏的摘要
- Joshua Bloch对ThreadLocals的看法
参考: 如何与我们的JCG合作伙伴 Nikita Salnikov Tarnovski (来自Plumbr Blog博客) 一起使用ThreadLocals进行射击 。
翻译自: https://www.javacodegeeks.com/2013/01/how-to-shoot-yourself-in-foot-with-threadlocals.html