使用threadlocal

正如我们的读者可能已经猜到的那样,我每天都会处理内存泄漏。 最近,一种特殊类型的OutOfMemoryError消息开始引起我的注意-滥用ThreadLocals引发的问题变得越来越频繁。 在查看此类泄漏的原因时,我开始相信其中一半以上是由于开发人员导致的,他们要么不知道自己在做什么,要么正试图对并非旨在解决的问题采用解决方案。 。

我决定不发表文章,而是发表两篇文章来打开这个话题,您目前正在阅读第一篇。 在帖子中,我解释了ThreadLocal使用背后的动机。 在当前正在进行的第二篇文章中,我将打开ThreadLocal帽子并查看实现。

让我们从一个虚构的场景开始,其中ThreadLocal的使用确实是合理的。 为此,请与我们的假设开发人员Tim打个招呼。 蒂姆(Tim)正在开发一个Webapp,其中包含许多本地化内容。 例如,来自加利福尼亚的用户可能希望使用熟悉的MM / dd / yy模式格式化日期,而来自爱沙尼亚的用户则希望看到根据dd.MM.yyyy格式化的日期 因此,Tim开始编写如下代码:

public String formatCurrentDate() {DateFormat df = new SimpleDateFormat("MM/dd/yy");return df.format(new Date());}public String formatFirstOfJanyary1970() {DateFormat df = new SimpleDateFormat("MM/dd/yy");return df.format(new Date(0));}

过了一会儿,Tim觉得这很无聊并且违反了良好做法–应用程序代码被此类初始化污染了。 因此,他通过将DateFormat提取到实例变量中采取了看似合理的措施。 采取行动之后,他的代码现在如下所示:

private DateFormat df = new SimpleDateFormat("MM/dd/yy");public String formatCurrentDate() {return df.format(new Date());}public String formatFirstOfJanyary1970() {return df.format(new Date(0));}

Tim对重构结果感到满意,Tim向自己扔了一个假想的高五,将更改推送到存储库中,然后回家。 几天后,用户开始抱怨–其中一些字符串似乎完全乱码,而不是以前格式正确的日期。

研究问题Tim发现DateFormat实现不是线程安全的。 这意味着在上述情况下,如果两个线程同时使用formatCurrentDate()formatFirstOfJanyary1970()方法,则状态可能会混乱,显示的结果可能会混乱。 因此,Tim通过限制对方法的访问以确保一次输入一个线程进入格式化功能来解决此问题。 现在,他的代码如下所示:

private DateFormat df = new SimpleDateFormat("MM/dd/yy");public synchronized String formatCurrentDate() {return df.format(new Date());}public synchronized String formatFirstOfJanyary1970() {return df.format(new Date(0));}

在给自己另一个虚拟的高五后,蒂姆做出了改变并去了一个漫长的假期。 第二天才开始收到电话,抱怨应用程序的吞吐量急剧下降。 深入研究问题后,他发现同步访问已在应用程序中造成了意外的瓶颈。 现在,线程不必再随意输入格式化部分了,而必须彼此等待。

进一步阅读该问题,Tim发现了另一种类型的变量ThreadLocal 。 这些变量与普通变量不同,因为每个访问一个线程(通过ThreadLocal的get或set方法)的线程都有其自己的,独立初始化的变量副本。 对于新发现的概念感到满意,Tim再次重写了代码:

public static ThreadLocal df = new ThreadLocal() {protected DateFormat initialValue() {return new SimpleDateFormat("MM/dd/yy");}};public String formatCurrentDate() {return df.get().format(new Date());}public String formatFirstOfJanyary1970() {return df.get().format(new Date(0));}

经过这样的过程,蒂姆通过痛苦的教训学到了一个强大的概念。 像在最后一个示例中那样应用后,结果可以很好地说明收益。

但是新发现的概念很危险。 如果Tim使用了应用程序类之一而不是引导类加载器加载的JDK捆绑的DateFormat类,那么我们已经处在危险区域。 只是忘记在手头的任务完成后将其删除,该对象的副本将保留在线程中,该线程通常属于线程池。 由于池化线程的寿命超过了应用程序的寿命,因此它将防止对象被垃圾回收,从而防止ClassLoader负责加载应用程序。 而且我们创建了一个泄漏,有机会以一种很好的旧java.lang.OutOfMemoryError:PermGen空间形式浮出水面。

另一种开始滥用该概念的方法是通过使用ThreadLocal作为在应用程序中获取全局上下文的黑客。 顺其自然,这是一种处理应用程序代码的可靠方法,它具有各种无法想象的依赖关系,从而将整个代码库陷入难以维护的混乱之中。

参考: 何时以及如何使用我们的JCG合作伙伴 Nikita Salnikov Tarnovski (来自Plumbr博客) 的ThreadLocal 。

翻译自: https://www.javacodegeeks.com/2013/10/when-and-how-to-use-a-threadlocal.html

使用threadlocal

使用threadlocal_何时以及如何使用ThreadLocal相关推荐

  1. threadlocal_了解ThreadLocal背后的概念

    threadlocal 介绍 我知道本地线程,但直到最近才真正使用过它. 因此,我开始深入研究该主题,因为我需要一种传播某些用户信息的简便方法 通过Web应用程序的不同层,而无需更改每个调用方法的签名 ...

  2. FastThreadLocal吞吐量居然是ThreadLocal的3倍

    目前关于FastThreadLocal的很多文章都有点老有点过时了(本文将澄清几个误区),很多文章关于FastThreadLocal介绍的也不全,希望本篇文章可以带你彻底理解FastThreadLoc ...

  3. 正确理解ThreadLocal

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt107 首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的, ...

  4. 什么是ThreadLocal

    顾名思义它是local variable(线程局部变量).它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突.从线 ...

  5. 为什么jdk源码推荐ThreadLocal使用static

    ThreadLocal是线程私有变量,本身是解决多线程环境线程安全,可以说单线程实际上没必要使用. 既然多线程环境本身不使用static,那么又怎么会线程不安全.所以这个问题本身并不是问题,只是有人没 ...

  6. Spring源码分析【6】-ThreadLocal的使用和源码分析

    Spring代码使用到了ThreadLocal java.lang.ThreadLocal.set getMap java.lang.Thread.threadLocals定义 回到set 如果map ...

  7. threadlocal使用场景_深入剖析ThreadLocal

    点击上方 IT牧场 ,选择 置顶或者星标 技术干货每日送达 朋友们在遇到线程安全问题的时候,大多数情况下可能会使用synchronized关键字,每次只允许一个线程进入锁定的方法或代码块,这样就可以保 ...

  8. ThreadLocal源码分析

    ThreadLocal的作用 Java对象是线程间共享的,但有时我们需要一些线程间隔离的对象,该对象只能由同一个线程读写,对其他线程不可见.ThreadLocal正式提供了这样的机制,详细使用方式请参 ...

  9. ThreadLocal的使用场景

    最近项目中遇到如下的场景:在执行数据迁移时,需要按照用户粒度加锁,因此考虑使用排他锁,迁移工具和业务服务属于两个服务,因此需要使用分布式锁. 我们使用缓存(Tair或者Redis)实现分布式锁,具体代 ...

最新文章

  1. 【串讲总结】RNN、LSTM、GRU、ConvLSTM、ConvGRU、ST-LSTM
  2. Spock是什么?它和JUnit,JMock有什么区别?
  3. 甩锅!偷懒!PUA!转嫁压力!铲除异己!压榨下属!这就是职场leader真面目!...
  4. log4j2在spring中的配置
  5. 美空管官员:政府停摆致人手不足 危及航空安全
  6. 【PAT甲级 排序】1012 The Best Rank (25 分) C++ 全部AC
  7. 有一种爱情叫永不改变_设计就像爱情一样,总是在寻找一种方式
  8. .NET 云原生架构师训练营(设计原则设计模式)--学习笔记
  9. php5.6 pdo.dll 没有,php5.6没有pdo怎么办
  10. 方差分析中的“元”和“因素”是什么?
  11. 【实用工具】之VMware workstation 14中安装CentOS 7
  12. service程序改为windows窗体展示
  13. 构建安全驱动型网络,Fortinet荣誉2020 Gartner广域网边缘基础设施领导者的源力
  14. 10 种最流行的 Web 挖掘工具!
  15. 计算机上无线网络开关在哪里,笔记本电脑无线网开关在哪_笔记本电脑如何打开无线网-win7之家...
  16. 【转】Linux内存管理(最透彻的一篇)
  17. 基于Springboot+Vue开发建筑工地用料管理系统
  18. python 操作ps脚本_Python实现PS图像调整颜色梯度效果示例
  19. oeasy教您玩转vim - 52 - # 正则查找
  20. k8s pod删不掉

热门文章

  1. BZOJ3527: [Zjoi2014]力 [FFT]
  2. 14、ORACLE下的基本SQL操作
  3. Properties文件的XML格式
  4. 直面Java第45期
  5. HashMap 实现原理
  6. 如何从Gitee中拉取项目到HBuilder中?
  7. 《走遍中国》珍藏版(八)
  8. git 拉取gitlab代码
  9. 铜仁学院计算机报名,铜仁学院2012年3月全国计算机等级考试报名时间通知
  10. 本地java判断zk节点是否存在