`

关于ThreadLocal模式的体会

阅读更多

写这篇帖子的目的不是为了来剖析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我们就可以用另外一种方式解决:

  1.   在某个接口中定义一个静态的ThreadLocal 对象,例如 public static ThreadLocal  threadLocal=new ThreadLocal ();
  2.   然后让a,b,c方法所在的类假设是类A,类B,类C都实现1中的接口
  3.   在调用a时,使用A.threadLocal.set(user) 把user对象放入ThreadLocal环境
  4.   这样我们在方法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()做了以下几件事:

  1. 得到当前线程Thread 对象
  2. 通过当前线程对象得到当前线程的ThreadLocalMap 对象
  3. 将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中存放的参数也被销毁。

 

 

 

分享到:
评论
16 楼 allengao 2010-03-17  
我记得过去测试过一次,在web中使用threadlocal保存变量,结果在线程消失后,变量值并没有自动清除,貌似request线程下,需要自己手动清除才可以,然后我们用threadlocal更多的情况下是为了保存dao,使其单例才可以完成方法的事务的完整性传播特性,用户对象这种个人认为没有必要threadlocal来保存。
15 楼 jcs7575 2010-03-17  
61234865 写道
我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?



可以用拦截器,每次有请求都重新赋值,比如从session中取出放到ThreadLoacl中
用他的好处就是不用传参数
14 楼 deyami 2010-03-17  
抛出异常的爱 写道
不知道有哪个项目是这么用的.

可以解决很多参数问题.



为什么没人说webwork?
13 楼 lkf520java 2010-03-17  
抛出异常的爱 写道
61234865 写道
我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?

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

如果同此请求也会丢失,那ThreadLocal不是成鸡肋了?
难道tomcat处理的请求的时候,不能够保证同一个请求只使用同一个线程处理?
12 楼 lkf520java 2010-03-17  
61234865 写道
我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?

   不知道你看清楚上面写的文章没有。ThreadLocal只能充当当前线程的Context,线程结束,当前线程ThreadLocal中存放的变量也被销毁了。
   但是这里必须注意的是:我们通常所用的tomcat中所使用的是线程池技术,即我们在web开发中,每个请求所使用的线程不一定都被销毁了(有可能被放回线程池中),即存放在其中的变量也没有被销毁。在这种前提我们必须注意一下几点:
  1. 我们却无法保证二次请求之间使用的是同一个线程,所以二次请求之间ThreadLocal不能共享
  2. 即使能保证,那也会出现问题,因为所有ThreadLocalMap中存放的key都是一样,如果你取得的线程之前已经被另外的线程使用过,这个时候,你从ThreadLocalMap取得的变量有可能不是你原来存放的变量,会出现一些未知的错误,所以如果我们在使用ThreadLocal的时候,如果是在线程池的环境下,那我们每次使用完ThreadLocal后,记得把里面的变量清空。
   
     所以对应在web开发中,我们必须认为ThreadLocal的作用域跟request对象一样,ThreadLocal中存放的变量对应一次请求到结束,第二次我们再使用ThreadLocal时,再重新往里面存放变量。
11 楼 hillshills 2010-03-17  


是呀,我们把threadlocal放在session中
10 楼 allengao 2010-03-17  
threadlocal内部貌似是使用了Thread.currentThread().getName()来当做key,在jdk1.5中是一种效率比较低的做法,据说在6.0速度有提升,但是实际中用途也不是很广泛,只有在权限系统或者保存数据库Connection时才会用到。
9 楼 accphc 2010-03-17  
传递分页参数
8 楼 iaimstar 2010-03-17  
抛出异常的爱 写道
不知道有哪个项目是这么用的.

可以解决很多参数问题.


俺们项目的session用这个鸟玩意
7 楼 抛出异常的爱 2010-03-17  
61234865 写道
我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?

同次请求的不丢就很了不起了.
6 楼 61234865 2010-03-17  
我有一个地方不太明白,就是我们用SSH的时候,如果你用threadlocal来存变量,你第二次请求的时候怎么能保证获取到的线程就是和先前的线程一样的?如果不一样,那数据岂不是就丢失了?
5 楼 lzstone 2010-03-17  
ThreadLocalMap  就是相当线程池的作用,用这个可以解释很多事物上的问题
4 楼 yimlin 2010-03-17  
通常用来解决框架中的上下文对象,业务级的通常还是传参解决,这样业务上更为明确。
3 楼 kingwon 2010-03-16  
类似AppEngine这种限制线程应用的平台,某些时候ThreadLocal成了唯一解决传参问题的方法
2 楼 lkf520java 2010-03-16  
抛出异常的爱 写道
不知道有哪个项目是这么用的.

可以解决很多参数问题.

其实我写这篇帖子,只是为了揭示ThreadLocal的本质作用,当然我们在实际开发和设计中,并不需要为了传参问题而使用ThreadLocal。但是我想基于ThreadLocal可以充当前线程的Context这种特性,可以让我们在实际项目的开发和设计中优美的解决更多问题。
1 楼 抛出异常的爱 2010-03-16  
不知道有哪个项目是这么用的.

可以解决很多参数问题.

相关推荐

    设计模式及ThreadLocal资料

    总结一下,这份资料涵盖了设计模式中的单例模式、工厂模式和代理模式,以及Java中的ThreadLocal特性。理解并熟练应用这些概念和技术,对于提升Java开发者的技能水平,优化代码的可读性和可维护性具有重要作用。在...

    Hibernate用ThreadLocal模式(线程局部变量模式)管理Session

    【ThreadLocal模式管理Session的理解】 在使用Hibernate进行数据库操作时,正确管理Session是优化系统性能的关键。Session由SessionFactory创建,而SessionFactory是线程安全的,这意味着它可以被多个并发线程共享...

    ThreadLocal应用示例及理解

    以上就是关于ThreadLocal的基本概念、使用方法、生命周期管理和实际应用示例的详细解释。了解并熟练掌握ThreadLocal可以帮助我们编写出更高效、更安全的多线程代码。在Java并发编程中,ThreadLocal是一个不可或缺的...

    ThreadLocal

    ThreadLocal是Java编程语言中的一个类,用于在多线程环境中提供线程局部变量。它是一种特殊类型的变量,每个线程都有自己的副本,互不影响,从而实现线程间数据隔离。ThreadLocal通常被用来解决线程共享数据时可能...

    理解threadlocal

    ### 理解ThreadLocal #### 一、ThreadLocal简介 `ThreadLocal`是一个非常有用的类,它在Java 1.2版本中被引入到`java.lang`包中。其主要功能是在多线程环境中为每个线程提供独立的变量副本,从而避免了线程之间的...

    理解ThreadLocal

    理解ThreadLocal 理解ThreadLocal 理解ThreadLocal 理解ThreadLocal

    正确理解ThreadLocal.pdf

    这种设计模式避免了在多线程环境中直接操作共享资源可能带来的线程安全问题。 #### 四、ThreadLocal的生命周期与内存管理 值得注意的是,`ThreadLocal`变量的生命周期与线程的生命周期紧密关联。当线程结束时,与...

    ThreadLocal 内存泄露的实例分析1

    在 `LeakingServlet` 的 `doGet` 方法中,如果 `ThreadLocal` 没有设置值,那么会创建一个新的 `MyCounter` 并设置到 `ThreadLocal` 中。关键在于,一旦 `MyCounter` 被设置到 `ThreadLocal`,那么它将与当前线程...

    java 简单的ThreadLocal示例

    Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,尤其在处理线程间数据隔离和共享时。ThreadLocal不是线程本身,而是为每个线程提供一个独立的变量副本,使得每个线程都可以独立地改变...

    ThreadLocal整理.docx

    ThreadLocal 整理 ThreadLocal 是 Java 中的一个重要组件,它能够在每个线程中保持独立的副本。这个功能是通过 Thread 类中的 threadLocals 属性来实现的,这个属性实际上是一个 Entry 数组,其中的每个 Entry 都...

    java事务 - threadlocal

    Java事务和ThreadLocal是两种在Java编程中至关重要的概念,它们分别用于处理多线程环境下的数据一致性问题和提供线程局部变量。 首先,我们来深入理解Java事务。在数据库操作中,事务是一系列操作的集合,这些操作...

    java中ThreadLocal详解

    ### Java中ThreadLocal详解 #### 一、ThreadLocal概述 在Java多线程编程中,`ThreadLocal`是一个非常重要的工具类,它提供了一种在每个线程内部存储线程私有实例的方法。通常情况下,当多个线程共享某个变量时,...

    ThreadLocal简单Demo

    **线程局部变量(ThreadLocal)** 在Java编程中,`ThreadLocal`是...以上就是关于`ThreadLocal`及其内部类`ThreadLocalMap`的基础知识,它们在多线程编程中起到关键作用,帮助开发者实现高效、安全的线程局部变量管理。

    ThreadLocal的几种误区

    ThreadLocal是Java编程中一种非常特殊的变量类型,它主要用于在多线程环境下为每个线程提供独立的变量副本,从而避免了线程间的数据共享和冲突。然而,ThreadLocal在理解和使用过程中容易产生一些误区,这里我们将...

    threadLocal

    ThreadLocal是Java编程语言中的一个线程局部变量类,它为每个线程提供了一个独立的变量副本,使得每个线程可以独立地改变自己的副本,而不会影响其他线程所对应的副本。这个特性在多线程环境下处理并发问题时非常...

    ThreadLocal详解.md

    学习ThreadLocal,了解其中的原理,以及学习其中的优点!避免坑点!!

    事务的封装和Threadlocal实例

    在默认情况下,JDBC连接是非自动提交模式,这意味着每条SQL语句执行后,如果未显式提交,事务会一直持续到程序结束或遇到异常。要手动控制事务,我们需要调用`Connection`对象的`setAutoCommit(false)`方法来禁用...

Global site tag (gtag.js) - Google Analytics