Java中的线程本地存储

线 开发人员中鲜为人知的功能之一是线程本地存储。 这个想法很简单,并且在需要数据的情况下很有用。 如果我们有两个线程,则它们引用相同的全局变量,但我们希望它们具有彼此独立初始化的单独值。


大多数主要的编程语言都有该概念的实现。 例如,C ++ 11甚至具有thread_local关键字,Ruby选择了一种API 方法 。

从1.2版开始,Java还使用java.lang.ThreadLocal <T>及其子类java.lang.InheritableThreadLocal <T>来实现该概念,因此这里没有什么新鲜的东西。

假设由于某种原因,我们需要为线程指定一个Long特定值。 使用线程本地将很简单:

public class ThreadLocalExample {public static class SomethingToRun implements Runnable {private ThreadLocal threadLocal = new ThreadLocal();@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " " + threadLocal.get());try {Thread.sleep(2000);} catch (InterruptedException e) {}threadLocal.set(System.nanoTime());System.out.println(Thread.currentThread().getName() + " " + threadLocal.get());}}public static void main(String[] args) {SomethingToRun sharedRunnableInstance = new SomethingToRun();Thread thread1 = new Thread(sharedRunnableInstance);Thread thread2 = new Thread(sharedRunnableInstance);thread1.start();thread2.start();}}

以下代码的一个可能示例运行将导致:

Thread-0 nullThread-0 132466384576241Thread-1 nullThread-1 132466394296347

在开始时,两个线程的值都设置为null,显然每个线程都使用单独的值,因为在将Thread-0的值设置为System.nanoTime()之后 ,它不会对Thread-1的值产生任何影响如我们所愿,一个线程作用域的long变量。

一个不错的副作用是线程从各种类调用多个方法的情况。 他们都将能够使用相同的线程范围变量,而无需进行重大的API更改。 由于未明确传递价值,因此可能会难以测试且不利于设计,但这完全是一个单独的主题。

在哪些地区流行使用线程局部语言的框架?

作为Java中最受欢迎的框架之一,Spring在内部将ThreadLocals用于许多部分,可通过简单的github 搜索轻松显示。 大多数用法与当前用户的操作或信息有关。 实际上,这实际上是JavaEE世界中ThreadLocals的主要用途之一,例如在RequestContextHolder中存储当前请求的信息:

private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal<RequestAttributes>("Request attributes");

或UserCredentialsDataSourceAdapter中的当前JDBC连接用户凭据。

如果我们回到RequestContextHolder,则可以使用此类访问代码中任何位置的所有当前请求信息。

常见的用例是LocaleContextHolder ,它可以帮助我们存储当前用户的语言环境。

Mockito使用它来存储当前的“全局” 配置 ,如果我们看看那里的任何框架,那么我们也很有可能会找到它。

线程本机和内存泄漏

我们了解了这个很棒的小功能,所以让我们在各处使用它。 我们可以做到这一点,但很少有Google搜索,而且我们发现那里的大多数人都说ThreadLocal是邪恶的。 并非完全正确,它是一个很好的实用程序,但在某些情况下可能容易造成内存泄漏。


“您是否可以通过线程局部变量导致意外的对象保留? 你当然可以。 但是您也可以使用数组来执行此操作。 这并不意味着线程局部变量(或数组)是坏事。 只是您必须谨慎使用它们。 使用线程池需要格外小心。 随意使用线程池与随意使用线程本地变量相结合会导致意外的对象保留,这在许多地方都已提到。 但是,将责任归咎于线程本机是没有根据的。” –约书亚·布洛赫(Joshua Bloch)

如果它在应用程序服务器上运行,则使用ThreadLocal在服务器代码中创建内存泄漏非常容易。 ThreadLocal上下文与运行它的线程相关联,一旦线程死掉,它将被丢弃。 现代的应用服务器使用线程池,而不是在每个请求上创建新线程,这意味着您最终可能会无限期地在应用程序中保存大型对象。 由于线程池来自应用程序服务器,因此即使卸载应用程序后,我们的内存泄漏仍会保留。 修复方法很简单,可以释放不需要的资源。

另一个ThreadLocal滥用是API设计。 我经常看到到处都在使用RequestContextHolder (它持有ThreadLocal ),例如DAO层。 后来,如果有人在诸如和调度程序之类的请求之外调用相同的DAO方法,他将得到一个非常糟糕的惊喜。

这使黑魔法和许多维护开发人员最终找到了您的住所并进行了访问。 即使ThreadLocal中的变量是线程本地的,它们在代码中还是非常全局的。 使用它之前,请确保您确实需要此线程作用域。

有关该主题的更多信息

  • http://en.wikipedia.org/wiki/Thread-local_storage
  • http://www.appneta.com/blog/introduction-to-javas-threadlocal-storage/
  • https://plumbr.eu/blog/how-to-shoot-yourself-in-foot-with-threadlocals
  • http://stackoverflow.com/questions/817856/when-and-how-should-i-use-a-threadlocal-variable
  • https://plumbr.eu/blog/when-and-how-to-use-a-threadlocal
  • https://weblogs.java.net/blog/jjviana/archive/2010/06/09/dealing-glassfish-301-memory-leak-or-threadlocal-thread-pool-bad-ide
  • https://software.intel.com/zh-CN/articles/use-thread-local-storage-to-reduce-synchronization

翻译自: https://www.javacodegeeks.com/2014/12/thread-local-storage-in-java.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361192.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jsp中@import导入外部样式表与link链入外部样式表的区别

昨天碰到同事问了一个问题&#xff0c;impor导入外部样式与link链入外部样式的优先级是怎样的&#xff0c;为什么实验的结果是按照样式表导入后的位置来决定优先级。今天就这个问题具体总结如下&#xff1a; 先解释一下网页添加css样式的方法&#xff0c;一共有四种&#xff0c…

EBS调试

一、在请求中的调试&#xff1a; 1、用系统函数fnd_file.PUT_LINE()&#xff0c;然后在请求的查看日志中就可以看到 例如&#xff1a; fnd_file.PUT_LINE(fnd_file.log, l_customer_type); 其中l_customer_type就是要查看的变量。 2、先建一张表&#xff0c;然后在程序中执行…

Acision推出“ forgeathon” –第一个WebRTC应用挑战

Acision推出了“ forgeathon”&#xff0c;这是 面向全球开发人员的 首个在线丰富网络通信&#xff08;WebRTC&#xff09;应用挑战 加入Forgeathon&#xff0c;让Acision帮助您将应用程序或服务推向全球&#xff01; 英国雷丁– 2015年1月6 日 &#xff1a;安全&#xff0c;…

SQL Server 中的ROWID

在SQL Server中没有像Orcal中的rowid&#xff0c;但是可以运用一定的变通达到这个效果。1、建立临时表&#xff0c;其中包含rowid&#xff0c;2、重命名原表后删除临时表USE TianzxSELECT identity(int,1,1) as rowid,flow.* into temptable from flow--建立临时表&#xff0c;…

jsp中四种传递参数的方法

jsp中四种传递参数的方法如下&#xff1a; 1、form表单 2、request.setAttribute();和request.getAttribute(); 3、超链接&#xff1a;<a herf"index.jsp"?aa&bb&cc>name</a> 4、<jsp:param> 下面一一举例说明&#xff1a; 1、form表…

多个退货单

我曾经听说过&#xff0c;过去人们为使方法具有单个出口点而奋斗。 我知道这是一种过时的方法&#xff0c;从未认为它特别值得注意。 但是最近&#xff0c;我与一些仍坚持该想法的开发人员进行了联系&#xff08;最后一次是在这里 &#xff09;&#xff0c;这让我开始思考。 因…

GO 语言编程 windows 环境搭建

参考 : http://blog.csdn.net/love_se/article/details/7754274 首先是安装Go&#xff0c;这里有很详细的安装说明&#xff0c;http://code.google.com/p/golang-china/wiki/Install 或者http://golang.org/doc/install 下面我们在window下面安装&#xff0c;google有提供win安…

建立代理,而不是框架

自从引入Java注释以来&#xff0c;它已成为大型应用程序框架API的组成部分。 此类API的良好示例是Spring或Hibernate的示例&#xff0c;其中添加了几行注释代码可实现非常复杂的程序逻辑。 尽管人们可以争论这些特定API的缺点&#xff0c;但大多数开发人员都会同意&#xff0c;…

HttpServletRequest.getContextPath()取得的路径

如果项目名称为test,你在浏览器中输入请求路径&#xff1a;http://localhost:8080/test/pc/list.jsp 执行下面向行代码后打印出如下结果&#xff1a; 1、 System.out.println(request.getContextPath()); 打印结果&#xff1a;/test 2、System.out.println(request.getSer…

合理的嵌入式开发学习路线

最近网上好多新手问我&#xff0c;怎么样学习嵌入式开发&#xff1f;其实这个问题很复杂&#xff0c;因为嵌入式开发是个非常复杂的领域&#xff0c;既有深度&#xff0c;也有广度&#xff0c;是个软硬结合的领域。。。我研究的时间也不长&#xff0c;不过以后可能会研究RTOS这…

重点保护

在“ Java的一些句子 ”一文中&#xff0c;我写道&#xff1a; “受保护的方法和字段可以在同一包中的类中使用&#xff08;到目前为止与私有包相同&#xff09;&#xff0c;此外&#xff0c;还可以从其他类中使用受保护的方法和字段&#xff0c;这些类扩展了包含受保护的字段或…

机打发票打印管理

最近公司也从手写发票换成了机打发票&#xff0c;便应财务的要求做了这么一个简单的发票管理及打印系统&#xff0c;程序并不复杂。 使用C#&#xff08;2.0&#xff09; Access&#xff08;97-2003版&#xff09;/WinForm形式 系统菜单中有企业基本信息设置&#xff0c;见图4…

程序员需要了解的一点组织行为学知识

程序员由于天天和逻辑打交道&#xff0c;所以在世故的人眼里往往显得过于简单。 近来看组织行为学&#xff0c;发现其中一节列了很多特别的技能。 考虑到也许他们对程序员群体很有启示意义&#xff0c;就追加了一点说明&#xff0c;把它放在博客里。 相信这对想成为管理者的程序…

序列化的概念

讨论了为什么Optional不可序列化以及如何处理&#xff08;即将推出&#xff09;之后&#xff0c;让我们仔细看看序列化。 总览 这篇文章介绍了序列化的一些关键概念。 它尝试精简地执行此操作&#xff0c;而不会涉及太多细节&#xff0c;包括将建议降至最低。 它没有叙述&…

正则表达式总结及一些有用的例子

背景 正则表达式的用处十分广泛&#xff1a;字符串处理、输入验证等&#xff0c;特别是在爬取网页中对网页内容的清洗更需要正则。 正则表达式 基本所有的语言都支持正则表达式&#xff0c;或者内置或者引入。正则的语法很多&#xff0c;但每种语言对正则支持的程度都不同&…

对PostgreSQL SPI例子的学习

[作者&#xff1a;技术者高健博客园 mail: luckyjackgaogmail.com ] http://www.postgresql.org/docs/9.1/static/spi-examples.html SPI 的例子里面没有说&#xff0c;是如何编译和部署的&#xff0c;我这里补充下&#xff1a; 编译与部署&#xff1a; [rootlocalhost soft]#…

Java飞行记录器(JFR)

JFR是Java分析器&#xff0c;它使您可以研究代码的运行时特征。 通常&#xff0c;您将使用探查器来确定代码的哪些部分导致大量内存分配或导致消耗过多的CPU。 有很多产品在那里。 过去&#xff0c;我使用过YourKit&#xff0c;OptimizeIt&#xff0c;JProfiler&#xff0c;Ne…

图像识别SLIC、Haralick texture features(自备)

SLIC 简单线性迭代聚类(SLIC ),它采用k-means聚类方法来有效地生成超像素。 SLIC超像素分割详解&#xff08;一&#xff09;&#xff08;二&#xff09;&#xff08;三&#xff09;_超像素分割 样本-CSDN博客 超像素分割 & SLIC算法 & 使用示例_slic分割算法matlab-C…

DOM

1 标签操作 直接查找 documeny.getElementById() 间接查找 文件内容&#xff1a; 1.innterText只有文本 2.innerHTML所有内容 3.value input便签 value 获取当前标签中的值 select标签 value 获取当前选中的value selectedIndex 设定当前选中的value textarea标签…

在Java中给出的时间

tl; dr&#xff0c;您可以使用标签来阐明给定的测试时间样式。 什么时候给出&#xff1f; 给定的时间&#xff0c;然后是一种指定系统行为的常用样式&#xff0c;其中您的测试分为三个部分。 给定的部分列出了测试的前提条件&#xff0c;即在开始之前假设世界所处的任何状态。…