2020/04/05 17:15
楼主文章都写的太棒了!!!
2018/03/05 17:59
赞一下
2015/12/09 15:22
这是我见过写的最明白的博文了。79
2015/10/12 16:43

引用来自“夕水溪下”的评论

ThreadLocalMap 是Thread 对象的属性,会随着Thread 对象的回收而回收,但是很多容器都有线程池,我们很多时候还需要手动移除!

引用来自“WinWill2012”的评论

楼主理解得好像有点点问题,建议大家去看看这篇文章吧 http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/ 比较深入详细地介绍了ThreadLocal的实现原理,并讨论了ThreadLocal到底会不会引发内存泄露。
文章写的很好,比我的理解深入多了,博客逼格很高
2015/10/12 16:30
只是你们两要说的侧重点不一样,ThreadLocal的确都可以应用再两种途径上面,至于他的最初的目的已经不重要了,java最初的设计目的且并不是为了侧重大型WEB项目呢,呵呵 你们说呢
2015/10/12 16:28

引用来自“夕水溪下”的评论

ThreadLocalMap 是Thread 对象的属性,会随着Thread 对象的回收而回收,但是很多容器都有线程池,我们很多时候还需要手动移除!

引用来自“WinWill2012”的评论

楼主理解得好像有点点问题,建议大家去看看这篇文章吧 http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/ 比较深入详细地介绍了ThreadLocal的实现原理,并讨论了ThreadLocal到底会不会引发内存泄露。
层主的这篇文章分析的的确在理,不过楼主的文章也不错,建议都看看 。。
2015/09/04 01:38

引用来自“夕水溪下”的评论

ThreadLocalMap 是Thread 对象的属性,会随着Thread 对象的回收而回收,但是很多容器都有线程池,我们很多时候还需要手动移除!
楼主理解得好像有点点问题,建议大家去看看这篇文章吧 http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/ 比较深入详细地介绍了ThreadLocal的实现原理,并讨论了ThreadLocal到底会不会引发内存泄露。
2015/09/02 10:13
同意三楼的看法,Threadlocal的出现并不是为了解决线程安全的问题,建议先看看这篇文章:http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal
分析了ThreadLocal的实现原理以及是否会出现内存泄露
HLA
2015/08/22 21:29
网上看了这么多关于ThreadLocal的介绍,这篇说到点子上了!很清晰!感谢楼主分享!
2015/01/13 14:20
看着评论 脾气挺大的呵呵
2014/09/14 15:20
一个ThreadLocal实例像一个代理,有自己的id(即hash code)。每个访问它的线程实际上访问了自己的threadLocals,然后通过id去访问线程里面的获取内容。
2014/08/07 17:25

引用来自“wf2030”的评论

引用来自“相见欢”的评论

引用来自“wf2030”的评论

threadlocal的出现并不是为了解决线程安全的问题

那请教一下,你认为它的出现是为了解决什么呢?你对它又是怎么理解的?

说实话,我对它理解不是很深,就是发表一下个人观点。如果有错,欢迎纠正。
我们想想线程安全是是什么?
多线程并发访问共享资源,对共享资源造成的读写不一致,是为了解决这个问题才出现的线程安全的问题,说到底,是都要对共享资源读写。
现在这个threadlocal为每个线程搞了一个副本(相当于在每个线程内部加了一个变量,当然threadlocal与局部变量还是不一样的,这里就不讨论这个问题了,暂且先允许我这么说吧),读写操作与其他线程无关,这跟多线程都要读取同一资源毛关系都没有。
假如x初始为10,线程A读取x为10,设置其为20,B又来了,读到的又是10,现在“安全”是“安全”了,但是对于共享资源x(注意这里说的是“共享”),现在B要的就是最后一个线程修改后的x的值,你给我一个之前我自己设置的值,有什么用呢?
是的
2014/05/08 17:07
抱歉,不敢苟同。使用ThreadLocal会产生线程引用问题,导致内存泄露。
2014/05/04 16:34
看完评论,我觉得把java中ThreadLocal或者TLS理解为保存线程的上下文比较好。比如有很多线程有类似的上下文结构,最后都需要根据上下文做一些处理。方法是定义一个上下文对象,每个线程持有这样一个对象。而thread中的ThreadLocalMap对象就相当于这样一个上下文对象,所谓的上下文一般都是所谓的“永久代”(不严密,比如静态变量等,当线程结束时才会被gc)。
2013/10/29 15:32

引用来自“eastwake”的评论

给你取这样一个典型的例子吧,你可以看到TLS实际的应用场合。

在一个支持单进程,多线程的轻量级移动平台中,假设我实现了一个APP Framework,每一个APP单独运行在一个独立的线程中,APP运行时关联了很多信息,比如打开的文件,引用的组件,启动的Timer等等。我希望框架能实现自动垃圾回收,什么概念,就会应用退出的时候,即便应用没有主动释放打开的文件句柄,没有主动cancel Timer,没有主动释放组件的引用,框架也可以自动完成这些收尾工作,否则,后果是不堪想象的。

好了,假设应用的退出是调用了框架的 ExitApp API, 该API允许应用调用后关闭自己,也允许关闭别的应用。 那么,假设该API触发了应用的退出,最终调用到框架的App_CleanUp函数,那么App_CleanUp函数除了完成应用本身实例的释放外,肯定是在这里来完成我们上面说的收尾工作,怎么来做哪?! 很明显,这里典型的,就可以使用TLS了。具体如下:

在Framework的API中,当应用的线程启动时,New 一个AppContext的对象或者结构体,然后将对象的指针或者结构体的指针以TLS的方式存储起来。 AppContext内部包含了文件句柄,timer引用,组件引用等等。 然后,后续任何框架的文件操作/Timer操作时,取当前线程的TLS,然后转换成AppContext后,将更新的文件句柄,timer引用等更新入AppContext对象内部。 然后,应用退出时,获取TLS,然后转换成AppContext,取出非空的文件句柄,组件引用,Timer引用等,来完成Cancel和Close操作。


其他不想说了,如果你能明白这个实际的例子,你就可以明白TLS的用途了。 上述的例子,来源于BREW/BMP框架内部的实际实现,当然有差别,但是思想是一样的

这位兄台说的甚合我意啊,其实就是自己管理自己
2013/06/17 16:22

引用来自“wf2030”的评论

引用来自“相见欢”的评论

引用来自“夕水溪下”的评论

引用来自“wf2030”的评论

引用来自“相见欢”的评论

引用来自“wf2030”的评论

threadlocal的出现并不是为了解决线程安全的问题

那请教一下,你认为它的出现是为了解决什么呢?你对它又是怎么理解的?

说实话,我对它理解不是很深,就是发表一下个人观点。如果有错,欢迎纠正。
我们想想线程安全是是什么?
多线程并发访问共享资源,对共享资源造成的读写不一致,是为了解决这个问题才出现的线程安全的问题,说到底,是都要对共享资源读写。
现在这个threadlocal为每个线程搞了一个副本(相当于在每个线程内部加了一个变量,当然threadlocal与局部变量还是不一样的,这里就不讨论这个问题了,暂且先允许我这么说吧),读写操作与其他线程无关,这跟多线程都要读取同一资源毛关系都没有。
假如x初始为10,线程A读取x为10,设置其为20,B又来了,读到的又是10,现在“安全”是“安全”了,但是对于共享资源x(注意这里说的是“共享”),现在B要的就是最后一个线程修改后的x的值,你给我一个之前我自己设置的值,有什么用呢?

ThreadLocal和Synchronized都是为了解决线程安全的问题,只不过ThreadLocal性能比较好,因为他不阻塞。你说的对共享资源造成的读写不一致,还不是线程安全么?

我知道@wf2030兄要表达的意思了,的确从效果上来说,ThreadLocal为每一个线程提供一份拷贝,变量线程隔离后,成了互不相干的东西。但是这不正是实现了这个变量的线程安全么?不管你每个变量如何折腾,都不会有线程安全问题,也无需任何额外的同步。回到文章最后,还是要看看这个变量“是否允许这样做”。如果这个变量一定是要求全局唯一,那么你就只能通过同步机制,在多个线程间共享它了。你把效果和目的搞混了

嗯,可能是程序猿干久了,表达能力有问题了。。。
确实是这个意思,就是说既然要共享一份资源,肯定是希望他是唯一的,所以这个问题也许是线程安全和线程同步的关系。。。

你是说线程同步不一定线程安全?
2013/06/17 16:13

引用来自“相见欢”的评论

引用来自“夕水溪下”的评论

引用来自“wf2030”的评论

引用来自“相见欢”的评论

引用来自“wf2030”的评论

threadlocal的出现并不是为了解决线程安全的问题

那请教一下,你认为它的出现是为了解决什么呢?你对它又是怎么理解的?

说实话,我对它理解不是很深,就是发表一下个人观点。如果有错,欢迎纠正。
我们想想线程安全是是什么?
多线程并发访问共享资源,对共享资源造成的读写不一致,是为了解决这个问题才出现的线程安全的问题,说到底,是都要对共享资源读写。
现在这个threadlocal为每个线程搞了一个副本(相当于在每个线程内部加了一个变量,当然threadlocal与局部变量还是不一样的,这里就不讨论这个问题了,暂且先允许我这么说吧),读写操作与其他线程无关,这跟多线程都要读取同一资源毛关系都没有。
假如x初始为10,线程A读取x为10,设置其为20,B又来了,读到的又是10,现在“安全”是“安全”了,但是对于共享资源x(注意这里说的是“共享”),现在B要的就是最后一个线程修改后的x的值,你给我一个之前我自己设置的值,有什么用呢?

ThreadLocal和Synchronized都是为了解决线程安全的问题,只不过ThreadLocal性能比较好,因为他不阻塞。你说的对共享资源造成的读写不一致,还不是线程安全么?

我知道@wf2030兄要表达的意思了,的确从效果上来说,ThreadLocal为每一个线程提供一份拷贝,变量线程隔离后,成了互不相干的东西。但是这不正是实现了这个变量的线程安全么?不管你每个变量如何折腾,都不会有线程安全问题,也无需任何额外的同步。回到文章最后,还是要看看这个变量“是否允许这样做”。如果这个变量一定是要求全局唯一,那么你就只能通过同步机制,在多个线程间共享它了。你把效果和目的搞混了

线程同步不就是为避免读到脏数据,而脏数据不就是因为变量全局唯一吗,我一直以为线程安全说的就是不会产生脏数据,然道线程同步和线程安全说的不是一回事吗?楼上说的就变成读到脏数据也算线程同步了,也等于是线程安全了吗,那是不是说项目里读到脏数据我就不能说是你线程没同步或线程不安全导致,那我应该怎么表达这类问题了?
2013/03/20 15:10
给你取这样一个典型的例子吧,你可以看到TLS实际的应用场合。

在一个支持单进程,多线程的轻量级移动平台中,假设我实现了一个APP Framework,每一个APP单独运行在一个独立的线程中,APP运行时关联了很多信息,比如打开的文件,引用的组件,启动的Timer等等。我希望框架能实现自动垃圾回收,什么概念,就会应用退出的时候,即便应用没有主动释放打开的文件句柄,没有主动cancel Timer,没有主动释放组件的引用,框架也可以自动完成这些收尾工作,否则,后果是不堪想象的。

好了,假设应用的退出是调用了框架的 ExitApp API, 该API允许应用调用后关闭自己,也允许关闭别的应用。 那么,假设该API触发了应用的退出,最终调用到框架的App_CleanUp函数,那么App_CleanUp函数除了完成应用本身实例的释放外,肯定是在这里来完成我们上面说的收尾工作,怎么来做哪?! 很明显,这里典型的,就可以使用TLS了。具体如下:

在Framework的API中,当应用的线程启动时,New 一个AppContext的对象或者结构体,然后将对象的指针或者结构体的指针以TLS的方式存储起来。 AppContext内部包含了文件句柄,timer引用,组件引用等等。 然后,后续任何框架的文件操作/Timer操作时,取当前线程的TLS,然后转换成AppContext后,将更新的文件句柄,timer引用等更新入AppContext对象内部。 然后,应用退出时,获取TLS,然后转换成AppContext,取出非空的文件句柄,组件引用,Timer引用等,来完成Cancel和Close操作。


其他不想说了,如果你能明白这个实际的例子,你就可以明白TLS的用途了。 上述的例子,来源于BREW/BMP框架内部的实际实现,当然有差别,但是思想是一样的
2013/03/20 14:39

引用来自“eastwake”的评论

对TLS更简单的,但是更直观的理解可以如下(基于C语言):

1. 全局对象,全局变量的作用域和生命周期是全局的,这里的全局是指进程范畴,也就是说,如果你将其设计为全局对象,全局变量,就意味着你希望在多线程的环境中,仍然能共享和访问。 全局对象,全局变量不是说不让多线程来访问,而是说有的时候不期望他们同时访问,此时引入了线程的互斥,互斥的后果是保证不同时访问,但是,并没有改变共享的本质!

2. 如果设计的时候,就希望将某个对象,变量设计为线程局部的,那典型的是可以将其设计为函数的局部变量。 可是,我如果又希望在线程执行时,任意的函数和对象里面都可以访问到它那?! 此时,可能会想到用全局对象,全局变量,但是,它又会使得这种访问域上升到进程级别,其实,我只是想在线程局部环境中,全局访问该对象。 此时TLS应运而生,TLS就是达到了这种, 在线程局部环境(或者称呼为线程执行环境,线程上下文)下可以全局访问的对象/变量。

关于TLS的实际应用,更多的是定义一个TLS对象来存储一些线程上下文相关的信息。

看来java语言中的ThreadLocal,也是脱胎于C语言中的这个概念。java中的一个ThreadLocal变量,就相当于声明了一个在线程局部环境(或者称呼为线程执行环境,线程上下文)下可以全局访问的对象/变量。它的确不是为了线程同步或互斥而生,在java中TLS解决了多线程访问变量的问题只是结果,不是目的,这样理解不知道是不是更好?
2013/03/20 13:24
对TLS更简单的,但是更直观的理解可以如下(基于C语言):

1. 全局对象,全局变量的作用域和生命周期是全局的,这里的全局是指进程范畴,也就是说,如果你将其设计为全局对象,全局变量,就意味着你希望在多线程的环境中,仍然能共享和访问。 全局对象,全局变量不是说不让多线程来访问,而是说有的时候不期望他们同时访问,此时引入了线程的互斥,互斥的后果是保证不同时访问,但是,并没有改变共享的本质!

2. 如果设计的时候,就希望将某个对象,变量设计为线程局部的,那典型的是可以将其设计为函数的局部变量。 可是,我如果又希望在线程执行时,任意的函数和对象里面都可以访问到它那?! 此时,可能会想到用全局对象,全局变量,但是,它又会使得这种访问域上升到进程级别,其实,我只是想在线程局部环境中,全局访问该对象。 此时TLS应运而生,TLS就是达到了这种, 在线程局部环境(或者称呼为线程执行环境,线程上下文)下可以全局访问的对象/变量。

关于TLS的实际应用,更多的是定义一个TLS对象来存储一些线程上下文相关的信息。
2013/03/20 13:05

引用来自“eastwake”的评论

TLS更多的是用来存储线程上下文相关的信息,使得在一致的代码中,自动访问差异性的线程绑定的上下文相关信息

汗颜!受教了,我对操作系统上面相关的相关概念没有太多了解,只在java上面坐井观天才写了这些东西,惭愧。
2013/03/20 11:56
TLS更多的是用来存储线程上下文相关的信息,使得在一致的代码中,自动访问差异性的线程绑定的上下文相关信息
2013/03/20 11:53
简直误人子弟,我在OSCHINA看到两篇关于ThreadLocal的文档了,都是说“ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题”。 TLS(Thread Local Storage) 是为了解决线程安全和并发访问共享资源的目的?! 线程互斥技术是为了解决,多个线程间共享的,大家都要访问和读写的资源,如何在线程并发时不会有问题,典型的打印机问题!注意,这里的资源,是需要在多个线程间共享的!

而TLS究竟是解决什么问题那? TLS解决了这样一个需求,就是希望在一个/每个线程的线程上下文/环境下执行的任何实体(函数,组件等)内,都能访问某一个变量。 那么很明显,这个变量是需要做成全局的,但是,普通全局的会污染别的线程。所以,此时需要TLS。 举个最简单的例子,假设我的程序会连续启动6个线程去创建文件,线程代码是完全一样的。那么,我就可以使用TLS来记录线程上下文中的文件句柄。此时,我使用一致的文件操作代码,却能保证不管在任何实体中操作的文件句柄,都自动的是当前线程下的打开文件的文件句柄
2013/03/19 22:29
TLS 是Thread local storage的含义
2013/03/19 21:49

引用来自“eastwake”的评论

不要由于java混淆了本质,其实就是TLS的概念,去问问搞linux的前辈,TLS的目的是为了线程同步和互斥?完全不能的概念

羞死了,完全没听说过TLS是什么,感谢鞭策
2013/03/19 21:43
不要由于java混淆了本质,其实就是TLS的概念,去问问搞linux的前辈,TLS的目的是为了线程同步和互斥?完全不能的概念
2013/03/18 11:42
ThreadLocalMap 大小 是不是始终为1呀?
2013/03/06 11:27
该评论暂时无法显示,详情咨询 QQ 群:点此入群
2013/03/06 11:26
那个ThreadLocal的例子是java concurrency in practice里面的。有空谢谢那本书The Java Memory Model这一章,特别是happens-before那里,看不懂
2013/03/04 16:30

引用来自“wf2030”的评论

@相见欢 还有刚才我看了一下Threadlocal的源码,里面已经没有了Threadlocalmap,取而代之的是Values静态类,我的JDK是最新的JDK7u15,Threadlocalmap估计是JDK6的?

JDK7又有新变化啊,我的是JDK6,还不想更新到JDK7
2013/03/04 15:44
@相见欢 还有刚才我看了一下Threadlocal的源码,里面已经没有了Threadlocalmap,取而代之的是Values静态类,我的JDK是最新的JDK7u15,Threadlocalmap估计是JDK6的?
2013/03/04 15:41

引用来自“相见欢”的评论

引用来自“夕水溪下”的评论

引用来自“wf2030”的评论

引用来自“相见欢”的评论

引用来自“wf2030”的评论

threadlocal的出现并不是为了解决线程安全的问题

那请教一下,你认为它的出现是为了解决什么呢?你对它又是怎么理解的?

说实话,我对它理解不是很深,就是发表一下个人观点。如果有错,欢迎纠正。
我们想想线程安全是是什么?
多线程并发访问共享资源,对共享资源造成的读写不一致,是为了解决这个问题才出现的线程安全的问题,说到底,是都要对共享资源读写。
现在这个threadlocal为每个线程搞了一个副本(相当于在每个线程内部加了一个变量,当然threadlocal与局部变量还是不一样的,这里就不讨论这个问题了,暂且先允许我这么说吧),读写操作与其他线程无关,这跟多线程都要读取同一资源毛关系都没有。
假如x初始为10,线程A读取x为10,设置其为20,B又来了,读到的又是10,现在“安全”是“安全”了,但是对于共享资源x(注意这里说的是“共享”),现在B要的就是最后一个线程修改后的x的值,你给我一个之前我自己设置的值,有什么用呢?

ThreadLocal和Synchronized都是为了解决线程安全的问题,只不过ThreadLocal性能比较好,因为他不阻塞。你说的对共享资源造成的读写不一致,还不是线程安全么?

我知道@wf2030兄要表达的意思了,的确从效果上来说,ThreadLocal为每一个线程提供一份拷贝,变量线程隔离后,成了互不相干的东西。但是这不正是实现了这个变量的线程安全么?不管你每个变量如何折腾,都不会有线程安全问题,也无需任何额外的同步。回到文章最后,还是要看看这个变量“是否允许这样做”。如果这个变量一定是要求全局唯一,那么你就只能通过同步机制,在多个线程间共享它了。你把效果和目的搞混了

嗯,可能是程序猿干久了,表达能力有问题了。。。
确实是这个意思,就是说既然要共享一份资源,肯定是希望他是唯一的,所以这个问题也许是线程安全和线程同步的关系。。。
2013/03/04 14:24

引用来自“相见欢”的评论

引用来自“aahuihui2010”的评论

引用来自“相见欢”的评论

引用来自“aahuihui2010”的评论

而且重点的threadlocalhashcode你也是没有讲到,剖根问底不深,往祖坟上刨刨

哈哈,刨根问底,刨个稀烂。这里刨的是ThreadLocal家的祖坟,ThreadLocalMap的祖坟我看是可以另外开一篇文章来刨:)

的确,毕竟这都是很优秀的设计,一篇博文是说不尽的

按兄弟你这个刨的速度,估计JDK源码是刨了一遍了,我还没刨多少呢:(

没有啊,那是个费时间的工程
2013/03/04 14:22

引用来自“aahuihui2010”的评论

引用来自“相见欢”的评论

引用来自“aahuihui2010”的评论

而且重点的threadlocalhashcode你也是没有讲到,剖根问底不深,往祖坟上刨刨

哈哈,刨根问底,刨个稀烂。这里刨的是ThreadLocal家的祖坟,ThreadLocalMap的祖坟我看是可以另外开一篇文章来刨:)

的确,毕竟这都是很优秀的设计,一篇博文是说不尽的

按兄弟你这个刨的速度,估计JDK源码是刨了一遍了,我还没刨多少呢:(
2013/03/04 14:16

引用来自“相见欢”的评论

引用来自“aahuihui2010”的评论

而且重点的threadlocalhashcode你也是没有讲到,剖根问底不深,往祖坟上刨刨

哈哈,刨根问底,刨个稀烂。这里刨的是ThreadLocal家的祖坟,ThreadLocalMap的祖坟我看是可以另外开一篇文章来刨:)

的确,毕竟这都是很优秀的设计,一篇博文是说不尽的
2013/03/04 14:13

引用来自“aahuihui2010”的评论

而且重点的threadlocalhashcode你也是没有讲到,剖根问底不深,往祖坟上刨刨

哈哈,刨根问底,刨个稀烂。这里刨的是ThreadLocal家的祖坟,ThreadLocalMap的祖坟我看是可以另外开一篇文章来刨:)
2013/03/04 14:12
该评论暂时无法显示,详情咨询 QQ 群:点此入群
2013/03/04 13:39
而且重点的threadlocalhashcode你也是没有讲到,剖根问底不深,往祖坟上刨刨
2013/03/04 13:33
楼主探讨不深,希望将threadlocalmap的实现机制也加入,是haspmap的同步还是hashtable,其实应该是hashmap的同步和扩展
2013/03/04 12:50
该评论暂时无法显示,详情咨询 QQ 群:点此入群
2013/03/04 11:46
该评论暂时无法显示,详情咨询 QQ 群:点此入群
2013/03/04 10:54

引用来自“wf2030”的评论

threadlocal的出现并不是为了解决线程安全的问题

那请教一下,你认为它的出现是为了解决什么呢?你对它又是怎么理解的?
2013/03/04 10:23
threadlocal的出现并不是为了解决线程安全的问题
2013/03/04 09:00

引用来自“夕水溪下”的评论

ThreadLocalMap 是Thread 对象的属性,会随着Thread 对象的回收而回收,但是很多容器都有线程池,我们很多时候还需要手动移除!

!兄弟说的有理,的确应该要考虑到线程池中的线程长时间不死亡带来的内存泄漏问题。
2013/03/03 23:01
ThreadLocalMap 是Thread 对象的属性,会随着Thread 对象的回收而回收,但是很多容器都有线程池,我们很多时候还需要手动移除!
回复 @
{{emojiItem.symbol}}
返回顶部
顶部