职业IT人-IT人生活圈

 找回密码
 成为会员
搜索
查看: 487|回复: 9

关于ThreadLocal模式的体会

[复制链接]
ksdal 发表于 2011-8-29 10:39 | 显示全部楼层 |阅读模式
写这篇帖子的目的不是为了来剖析ThreadLocal,因为坛子里有许多高手已经深入浅出的把ThreadLocal讲解的很清楚了。
特别是lujh99的正确理解ThreadLocal这篇帖子,通过JDK源代码把ThreadLocal讲得非常深入浅出,让我深受启发。我写这篇帖子的目的只是为再此作一个补充,想以另外一种通俗易懂的表达方式把自己对ThreadLocal理解写出来。


lujh99 写道
总之,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 中的?
lujh99 写道
将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。


   
    经过我的测试,正是如此,当我们调用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中存放的参数也被销毁。




木已 发表于 2011-8-29 10:39 | 显示全部楼层
不知道有哪个项目是这么用的.

可以解决很多参数问题.

feiguo 发表于 2011-8-29 10:39 | 显示全部楼层
抛出异常的爱 写道
不知道有哪个项目是这么用的.

可以解决很多参数问题.

其实我写这篇帖子,只是为了揭示ThreadLocal的本质作用,当然我们在实际开发和设计中,并不需要为了传参问题而使用ThreadLocal。但是我想基于ThreadLocal可以充当前线程的Context这种特性,可以让我们在实际项目的开发和设计中优美的解决更多问题。

走就走吧 发表于 2011-8-29 10:39 | 显示全部楼层
类似AppEngine这种限制线程应用的平台,某些时候ThreadLocal成了唯一解决传参问题的方法

fossil 发表于 2011-8-29 10:39 | 显示全部楼层
通常用来解决框架中的上下文对象,业务级的通常还是传参解决,这样业务上更为明确。

醉倚西风 发表于 2011-8-29 10:39 | 显示全部楼层
ThreadLocalMap  就是相当线程池的作用,用这个可以解释很多事物上的问题

郁闷小男人 发表于 2011-8-29 10:40 | 显示全部楼层
我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?

芷馨 发表于 2011-8-29 10:40 | 显示全部楼层
61234865 写道
我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?

同次请求的不丢就很了不起了.


yoyo 发表于 2011-8-29 10:40 | 显示全部楼层
抛出异常的爱 写道
不知道有哪个项目是这么用的.

可以解决很多参数问题.


俺们项目的session用这个鸟玩意

fossil 发表于 2011-8-29 10:40 | 显示全部楼层
传递分页参数
您需要登录后才可以回帖 登录 | 成为会员

本版积分规则

QQ|手机版|小黑屋|网站帮助|职业IT人-IT人生活圈 ( 粤ICP备12053935号-1 )|网站地图
本站文章版权归原发布者及原出处所有。内容为作者个人观点,并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是信息平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽造成漏登,请及时联系我们,我们将根据著作权人的要求立即更正或者删除有关内容。

GMT+8, 2024-4-27 14:24 , Processed in 0.134470 second(s), 20 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表