- 浏览: 196607 次
- 性别:
- 来自: 杭州
-
文章分类
最新评论
-
asdiy:
very good!原来是这个原因!
为什么会"well-known file is not secure" ? -
豆浆王子:
...
在Struts2的Action中取得请求参数值的几种方法 -
key232323:
skyfen 写道LZ是个很棒的人,加油!
+1
我四年的职业生涯,2010路在何方? -
skyfen:
LZ是个很棒的人,加油!
我四年的职业生涯,2010路在何方? -
y112300:
天下乌鸦一般黑,怎一个乱子了得
我四年的职业生涯,2010路在何方?
写这篇帖子的目的不是为了来剖析ThreadLocal,因为坛子里有许多高手已经深入浅出的把ThreadLocal讲解的很清楚了。
特别是lujh99的正确理解ThreadLocal这篇帖子,通过JDK源代码把ThreadLocal讲得非常深入浅出,让我深受启发。我写这篇帖子的目的只是为再此作一个补充,想以另外一种通俗易懂的表达方式把自己对ThreadLocal理解写出来。
1。每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。
2。将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。
正如lujh99 所言,ThreadLocal不是用来解决对象共享访问问题的,而是为了处理在多线程环境中,某个方法处理一个业务,需要递归依赖其他方法时,而要在这些方法中共享参数的问题。例如有方法a(),在该方法中调用了方法b(),而在b方法中又调用了方法c(),即a-->b--->c,如果a,b,c都需要使用用户对象,那么我们常用做法就是a(User user)-->b(User user)---c(User user)。但是如果使用ThreadLocal我们就可以用另外一种方式解决:
- 在某个接口中定义一个静态的ThreadLocal 对象,例如 public static ThreadLocal threadLocal=new ThreadLocal ();
- 然后让a,b,c方法所在的类假设是类A,类B,类C都实现1中的接口
- 在调用a时,使用A.threadLocal.set(user) 把user对象放入ThreadLocal环境
- 这样我们在方法a,方法b,方法c可以在不用传参数的前提下,在方法体中使用threadLocal.get()方法就可以得到user对象。
上面的类A,类B ,类C就可以分别对应我们做web开发时的 web层的Action--->业务逻辑层的Service-->数据访问层的DAO,当我们要在这三层中共享参数时,那么我们就可以使用ThreadLocal 了。
那么user对象是如何存放到ThreadLocal 中的?
经过我的测试,正是如此,当我们调用A.threadLocal.set(user) 时,set()做了以下几件事:
- 得到当前线程Thread 对象
- 通过当前线程对象得到当前线程的ThreadLocalMap 对象
- 将ThreadLocal静态实例作为key,user对象作值,存放到ThreadLocalMap 中。
PS:因为ThreadLocal是静态的,所以每个线程中的ThreadLocalMap的key都是相同的,不同的只是存放的容器ThreadLocalMap。
总结:
其实ThreadLocal 跟我们做web开发时使用的session对象的作用很类似,每当我们向服务器发送一个请求时,web服务器会为该请求创建一个线程,同时会为该请求创建一系列对象,其中包括session(当然在同一个浏览器发送的请求都获得是同一个session对象),所以当我们做web开发时,可以不用担心线程安全问题,自由的往session中存取变量,保存用户状态。同理,当我们在程序中第一次使用A.threadLocal.set(user) 存放参数时,不管在程序的哪个地方,我们都可以通过ThreadLocal 所在的接口访问静态threadLocal对象,同时来共享threadLocal存放的参数,threadLocal就相当于session的作用,来保存当前线程的状态。在我们开发实际开发中,可以任意往threadLocal中共享和存取自己需要的变量,只不过web中的session的生命周期在于客户端的浏览器,而threadLocal中存储的变量的生命周期只在于当前线程,当前结束,threadLocal中存放的参数也被销毁。
评论
ThreadLocal的本意是配合Thread以一种对象拷贝的方式解决多线程的互斥问题的。各自Thread维护自己的ThreadLocalMap,并以这个ThreadLocal的hashCode为key,用户对象为value。
如果lz用一个static的ThreadLocal,以这个ThreadLocal的hashcode()为key,User为value,并只在同一个线程里发挥作用的话,跟用public static Map,以Thread.currentThread().hashCode()为key,User为value,有什么区别吗?
threadlocal内部貌似是使用了Thread.currentThread().getName()来当做key,在jdk1.5中是一种效率比较低的做法,据说在6.0速度有提升,但是实际中用途也不是很广泛,只有在权限系统或者保存数据库Connection时才会用到。
额,你听谁说的??
JDK1.5的代码貌似如下:
private static synchronized int nextHashCode() { int h = nextHashCode; nextHashCode = h + HASH_INCREMENT; return h; }
这句话虽然说的没错,但千万不要利用线程销毁来清除ThreadLocal,正确的方法就像前面的doFilter例子那样,谁设置谁要负责清除。
所有服务器环境下都是用线程池缓存线程,由于线程不会(或不会立即)被销毁,ThreadLocal也不会被清除,更严重的问题是被缓存的线程的ThreadLocal不确定的会被用到其他服务请求处理中。
假如用ThreadLocal设置了user,而不及时清除,甚至会发生比较严重的安全问题。
这个问题的关键在于在web环境下怎么使用。
一般是使用Filter技术,在web.xml配置好,filter里的伪代码是这样:
doFilter(){ 设置threadlocal变量; filterChain.doFilter(); 清除threadlocal变量; }
这样就保证了在Action、JSP里都可以获得本线程的threadlocal变量。
注意:一次web 请求肯定是由一个线程来完成响应的。
这样的用法就更清析了...
不知道还有可能会出什么问题.....
不想用了新的用法会出什么隐问题
这样用就没问题了
doFilter(){ 设置threadlocal变量; try { filterChain.doFilter(); }finally { 清除threadlocal变量;} }
<div class="quote_div">
<p>[b][/b]</p>
<div class="quote_title">抛出异常的爱 写道</div>
<div class="quote_div">
<div class="quote_title">61234865 写道</div>
<div class="quote_div">我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?</div>
<br>同次请求的不丢就很了不起了. <br>
</div>
<p> </p>
<p> 第二次请求的时候和第一次请求的时候用的是同一个servlet实例。servlet是线程安全的对同一个servlet的请求容器只会实例会一个对像。</p>
</div>
<br>
开发是分层的,不仅jsp和servlet之间传递参数,包括service层、dao层之间传递
我不太同意这个观点,现在比如有如下的代码。这个format方法有2个线程循环的访问,每次访问完可以放回线程池中,但是因为SimpleDateFormat不是线程安全的类,所以这样访问肯定会出现并发的错误!
public class Foo { static SimpleDateFormat formator = new SimpleDateFormat("yyMMddHHmmss"); public static String format(Date date) { return formator.format(date); } }
那么为了避免并发的错误,可以有如下2中方案,1加synchronized,这样每次只有一个线程访问这个方法,对性能有影响
public static synchronized String format(Date date) { return formator.format(date); }
2,每次调用这个方法就生成一个新的SimpleDateFormat对象,这样会生成大量的对象,对性能不是很好
public static String format(Date date) { SimpleDateFormat formator = new SimpleDateFormat("yyMMddHHmmss"); return formator.format(date); }
那么如果用ThreadLocal就可以解决创建大量对象的问题和并发访问的问题,重复利用SimpleDateFormat对象
public class Foo { static ThreadLocal local = new ThreadLocal(); public static String format(Date date) { SimpleDateFormat formator = (SimpleDateFormat)local.get(); if (formator == null) { formator = new SimpleDateFormat("yyMMddHHmmss"); local.set(formator); } return formator.format(date); } }
这个我赞同

<div class="quote_title">抛出异常的爱 写道</div>
<div class="quote_div">
<div class="quote_title">61234865 写道</div>
<div class="quote_div">我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?</div>
<br>同次请求的不丢就很了不起了. <br>
</div>
<p> </p>
<p> 第二次请求的时候和第一次请求的时候用的是同一个servlet实例。servlet是线程安全的对同一个servlet的请求容器只会实例会一个对像。</p>
我不太同意这个观点,现在比如有如下的代码。这个format方法有2个线程循环的访问,每次访问完可以放回线程池中,但是因为SimpleDateFormat不是线程安全的类,所以这样访问肯定会出现并发的错误!
public class Foo { static SimpleDateFormat formator = new SimpleDateFormat("yyMMddHHmmss"); public static String format(Date date) { return formator.format(date); } }
那么为了避免并发的错误,可以有如下2中方案,1加synchronized,这样每次只有一个线程访问这个方法,对性能有影响
public static synchronized String format(Date date) { return formator.format(date); }
2,每次调用这个方法就生成一个新的SimpleDateFormat对象,这样会生成大量的对象,对性能不是很好
public static String format(Date date) { SimpleDateFormat formator = new SimpleDateFormat("yyMMddHHmmss"); return formator.format(date); }
那么如果用ThreadLocal就可以解决创建大量对象的问题和并发访问的问题,重复利用SimpleDateFormat对象
public class Foo { static ThreadLocal local = new ThreadLocal(); public static String format(Date date) { SimpleDateFormat formator = (SimpleDateFormat)local.get(); if (formator == null) { formator = new SimpleDateFormat("yyMMddHHmmss"); local.set(formator); } return formator.format(date); } }
很赞同你的观点。
可以解决很多参数问题.
举一个例子-CXF,很多很多。
是地,以前给项目国际化的时候用过这个。可以把rquest放在ThreadLocal里面,这样在任何方法内都可以得到当前登录用户,有时定义某个接口可能忽略了一些参数,可以这样做。。。
<p>如果在一个业务流程真的那么需要一个context存储上下文变量,那么我们应该找到一个map,把 “流程id映射map” 存储进去。</p>
<p>这样可以完全抛开Thread的概念,业务方法就不会把底层的东西都依赖进来。</p>
<p> </p>
<p>ThreadLocal还是应该应用在处理多线程的问题中。</p>
<p> </p>
<p> </p>
这个问题的关键在于在web环境下怎么使用。
一般是使用Filter技术,在web.xml配置好,filter里的伪代码是这样:
doFilter(){ 设置threadlocal变量; filterChain.doFilter(); 清除threadlocal变量; }
这样就保证了在Action、JSP里都可以获得本线程的threadlocal变量。
注意:一次web 请求肯定是由一个线程来完成响应的。
这样的用法就更清析了...
不知道还有可能会出什么问题.....
不想用了新的用法会出什么隐问题
这个问题的关键在于在web环境下怎么使用。
一般是使用Filter技术,在web.xml配置好,filter里的伪代码是这样:
doFilter(){ 设置threadlocal变量; filterChain.doFilter(); 清除threadlocal变量; }
这样就保证了在Action、JSP里都可以获得本线程的threadlocal变量。
注意:一次web 请求肯定是由一个线程来完成响应的。
<div class="quote_div">
<p>可以这么做,不过个人理解这是对ThreadLocal的误用。</p>
<p> </p>
<p>ThreadLocal充当当前线程的Context,同时也可以理解为ThreadLocal变量的作用域属于Thread。</p>
<p>业务方法的参数的生命周期可能是瞬态的,无端的放入ThreadLocal中会延长这些对象的生命周期,注意回收。</p>
<p>好的,我们会及时清理,如果真要这样做,还需要再写代码,不知有何优点。</p>
<p>同时这些业务方法没有了参数的描述会变得晦涩,还被强制的要求在同一线程的原理下工作。抽象依赖实现,不可取。</p>
<p> </p>
<p>PS:</p>
<p>“ThreadLocal不是用来解决对象共享访问问题的”------如果Java没有了多线程,大家还需要ThreadLocal么。</p>
<p>ThreadLocal 和 request的作用域完全是不同的。</p>
<p> </p>
</div>
<p> <br>其实对于ThreadLocal的这种特性,该如何使用,我觉得这个大家各有所需,各有所好,我就不在强调自己的观点。</p>
<p> </p>
<p>我也非常肯定你的观点:ThreadLocal 和request的作用域肯定是不相同的,ThreadLocal 中存放的变量的生命周期只存活于当前线程,而request的作用域在于一个请求处理结束。在tomcat的线程池环境下,基本上都是request处理完成后,线程都被回放到线程池,即request作用域结束,ThreadLocal 中ThreadLocalMap存放的变量也并没有被销毁。我说的是可以认为ThreadLocal 和 request的作用域是相同的 ,因为即使线程没被回收,我们也无非再找回之前处理过的线程,即使找回那个线程,那个线程也许被另外的request使用过,里面存放的是其他的参数,所以我在这里假设ThreadLocal 和 request的作用域是相同的是为了让大家明白,ThreadLocal 在实际使用过程中最好且也只有用于一次请求处理。</p>
<p> </p>
因为一般的servlet,JSP容器,都使用的线程池技术,所以当一个请求处理完成直到向客户端发送响应结束后,调度这个请求处理的线程没有被销毁而被放回线程池,所以threadlocal保存的变量也并没有被销毁,必须我们手动清除。
<p> </p>
<p>ThreadLocal充当当前线程的Context,同时也可以理解为ThreadLocal变量的作用域属于Thread。</p>
<p>业务方法的参数的生命周期可能是瞬态的,无端的放入ThreadLocal中会延长这些对象的生命周期,注意回收。</p>
<p>好的,我们会及时清理,如果真要这样做,还需要再写代码,不知有何优点。</p>
<p>同时这些业务方法没有了参数的描述会变得晦涩,还被强制的要求在同一线程的原理下工作。抽象依赖实现,不可取。</p>
<p> </p>
<p>PS:</p>
<p>“ThreadLocal不是用来解决对象共享访问问题的”------如果Java没有了多线程,大家还需要ThreadLocal么。</p>
<p>ThreadLocal 和 request的作用域完全是不同的。</p>
<p> </p>
发表评论
-
公司一些牛人的开放博客
2011-07-24 20:34 1081公司一些牛人的开放博客: 1 阿里中文站交互设计技术BLOG ... -
可伸缩性最佳实践:来自eBay的经验
2011-06-28 15:00 960原文转自http://www. ... -
走向架构师之路博文分享(转)
2011-02-18 11:54 1048原文转自http://cutesource.iteye.com ... -
Velocity china 2010会议的一些ppt资料
2010-12-09 15:04 1273RT,见附件 -
各种系统框架图简介
2010-10-29 11:39 2160原文出处:http://space.itpub.net/651 ... -
设计与开发Java服务器(转)
2010-08-13 16:31 792原文地址: 设计与开发应用服务器(一)------常见模式 ... -
(转贴)Ebay架构特点(HPTS 2009)
2010-07-30 14:09 1131原文转自http://www.tech-q.c ... -
代理模式的实现
2010-05-16 12:40 01.使用CGLIB 2.使用代理类
相关推荐
- **线程局部变量**:通过`ThreadLocal`类来隔离不同线程中的变量副本,从而避免线程安全问题。 ### 总结 本文从多线程的基础概念出发,深入探讨了Java中多线程的实现机制及线程安全问题,并介绍了几种常见的设计...
Java实验报告是对学习Java编程过程中进行的实践活动的记录和总结,通常包含实验目的、环境配置、实验内容、代码实现、运行结果以及实验体会等部分。这份"java实验报告(所有的完整的)"涵盖了全面的Java学习内容,...
这本"Java并发编程学习笔记"可能是作者在深入研究Java并发特性、工具和最佳实践过程中积累的心得体会。下面,我们将根据这个主题,探讨一些关键的Java并发编程知识点。 1. **线程与进程**:在多任务环境中,线程是...
在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!
前端分析-2023071100789
基于kinect的3D人体建模C++完整代码.cpp
搞机工具箱10.1.0.7z
GRU+informer时间序列预测(Python完整源码和数据),python代码,pytorch架构,适合各种时间序列直接预测。 适合小白,注释清楚,都能看懂。功能如下: 代码基于数据集划分为训练集测试集。 1.多变量输入,单变量输出/可改多输出 2.多时间步预测,单时间步预测 3.评价指标:R方 RMSE MAE MAPE,对比图 4.数据从excel/csv文件中读取,直接替换即可。 5.结果保存到文本中,可以后续处理。 代码带数据,注释清晰,直接一键运行即可,适合新手小白。
在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!
基于ANSYS LSDyna的DEM-SPH-FEM耦合模拟滑坡入水动态行为研究,基于ANSYS LSDyna的DEM-SPH-FEM耦合的滑坡入水模拟分析研究,基于ansys lsdyna的滑坡入水模拟dem-sph-fem耦合 ,基于ANSYS LSDyna; 滑坡入水模拟; DEM-SPH-FEM 耦合,基于DEM-SPH-FEM耦合的ANSYS LSDyna滑坡入水模拟
auto_gptq-0.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
复件 复件 建设工程可行性研究合同[示范文本].doc
13考试真题最近的t64.txt
好用我已经解决报错问题
# 踏入C语言的奇妙编程世界 在编程的广阔宇宙中,C语言宛如一颗璀璨恒星,以其独特魅力与强大功能,始终占据着不可替代的地位。无论你是编程小白,还是有一定基础想进一步提升的开发者,C语言都值得深入探索。 C语言的高效性与可移植性令人瞩目。它能直接操控硬件,执行速度快,是系统软件、嵌入式开发的首选。同时,代码可在不同操作系统和硬件平台间轻松移植,极大节省开发成本。 学习C语言,能让你深入理解计算机底层原理,培养逻辑思维和问题解决能力。掌握C语言后,再学习其他编程语言也会事半功倍。 现在,让我们一起开启C语言学习之旅。这里有丰富教程、实用案例、详细代码解析,助你逐步掌握C语言核心知识和编程技巧。别再犹豫,加入我们,在C语言的海洋中尽情遨游,挖掘无限可能,为未来的编程之路打下坚实基础!
auto_gptq-0.4.2-cp38-cp38-win_amd64.whl
自动立体库设计方案.pptx
# 踏入C语言的奇妙编程世界 在编程的广阔宇宙中,C语言宛如一颗璀璨恒星,以其独特魅力与强大功能,始终占据着不可替代的地位。无论你是编程小白,还是有一定基础想进一步提升的开发者,C语言都值得深入探索。 C语言的高效性与可移植性令人瞩目。它能直接操控硬件,执行速度快,是系统软件、嵌入式开发的首选。同时,代码可在不同操作系统和硬件平台间轻松移植,极大节省开发成本。 学习C语言,能让你深入理解计算机底层原理,培养逻辑思维和问题解决能力。掌握C语言后,再学习其他编程语言也会事半功倍。 现在,让我们一起开启C语言学习之旅。这里有丰富教程、实用案例、详细代码解析,助你逐步掌握C语言核心知识和编程技巧。别再犹豫,加入我们,在C语言的海洋中尽情遨游,挖掘无限可能,为未来的编程之路打下坚实基础!
在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!
在日常的工作和学习中,你是否常常为处理复杂的数据、生成高质量的文本或者进行精准的图像识别而烦恼?DeepSeek 或许就是你一直在寻找的解决方案!它以其高效、智能的特点,在各个行业都展现出了巨大的应用价值。然而,想要充分发挥 DeepSeek 的优势,掌握从入门到精通的知识和技能至关重要。本文将从实际应用的角度出发,为你详细介绍 DeepSeek 的基本原理、操作方法以及高级技巧。通过系统的学习,你将能够轻松地运用 DeepSeek 解决实际问题,提升工作效率和质量,让自己在职场和学术领域脱颖而出。现在,就让我们一起开启这场实用又高效的学习之旅吧!