`
wsmajunfeng
  • 浏览: 496840 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

正确理解ThreadLocal

 
阅读更多

 

首先, ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过 ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。 各个线程中访问的是不同的对象。

另外,说 ThreadLocal 使得各线程能够保持各自独立的一个对象,并不是通过 ThreadLocal.set() 来实现的,而是通过每个线程中进行 new 对象操作来创建对象,每个线程创建一个,不是什么对象的拷贝或副本。 通过 ThreadLocal.set() 将这个新创建的对象的引用保存到各线程自己的一个 mapThreadLocalMap )中,每个线程都有这样一个 map ,执行 ThreadLocal.get() 时,各线程从自己的此 mapThreadLocalMap )中取出放进去的对象,因此取出来的是各线程自己的对象, ThreadLocal 实例是作为 mapkey 来使用的。

如果 ThreadLocal.set() 进去的东西本来就是多个线程共享的同一个对象,那么多个线程的 ThreadLocal.get() 取得的还是这个共享对象本身,还是有并发访问问题。

下面来看一个 hibernate 中典型的 ThreadLocal 的应用:

 

 写道
private static final ThreadLocal threadSession = new ThreadLocal();

public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}

 

可以看到在 getSession() 方法中,首先判断当前线程中有没有放进去 Session 对象,如果还没有,那么通过 sessionFactory().openSession() 来创建一个 Session 对象( s ),再将此 session set 到线程中,实际是作为 value 放到当前线程的 ThreadLocalMap 这个 map 中,这时,对于这个 session 的唯一引用就是当前线程中的那个 ThreadLocalMap (下面会讲到),而 threadSession 是这个 map 中的 key ,要取得这个 session 可以通过 threadSession.get() 来得到,里面执行的操作实际是先取得当前线程中的 ThreadLocalMap ,然后将 threadSession 作为 key 将对应的值( session )取出。这个 session 相当于线程的私有变量,而不是 public 的。

显然,其他线程中是取不到这个 session 的,他们也只能取到自己的 ThreadLocalMap 中的东西。要是 session 是多个线程共享使用的,那还不乱套了。

试想如果不用 ThreadLocal 怎么来实现呢?可能就要在 action 中创建 session ,然后把 session 一个个传到 servicedao 中,这可够麻烦的。或者可以自己定义一个静态的 map ,将当前 threadThread.currentThread() )作为 key ,创建的 session 作为 valueputmap 中,应该也行,这也是一般人的想法,但事实上, ThreadLocal 的实现刚好相反,它是在每个线程中有一个 mapThreadLocalMap ),而将 ThreadLocal 实例作为 key ,这样每个 map 中的项数很少,而且当线程销毁时相应的东西也一起销毁了,不知道除了这些还有什么其他的好处。

总之, ThreadLocal 不是用来解决多线程访问共享对象问题的,而主要是提供了一种保存对象的方法和一种方便的避免参数传递麻烦的对象访问方式。归纳了两点:
1
、每个线程中都有一个自己的 ThreadLocalMap 类对象,可以将线程自己的对象(作为 value )保持到其中,各管各的,线程可以正确的访问到自己的对象。
2
、将一个共用的 ThreadLocal 静态实例作为 key ,将不同对象的引用保存到不同线程的 ThreadLocalMap 中,然后在线程执行的各处通过这个静态 ThreadLocal 实例的 get() 方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。

当然如果要把本来线程共享的对象通过 ThreadLocal.set() 放到线程中也可以,可以实现避免参数传递的访问方式,但是要注意 get() 到的是那同一个共享对象,并发访问问题要靠其他手段来解决。但一般来说线程共享的对象通过设置为某类的静态变量就可以实现方便的访问了,似乎没 必要放到线程中。

ThreadLocal 的应用场合,我觉得最适合的是按每个线程对应一个实例的方式访问对象,并且这个对象很多地方都要用到。比如:

一个验证流程包括很多验证环节,每个验证环节用一个类( validator )表示,每个验证环节都要用到同一个对象(比如会员类型: memberType ),也就是说这个 memberType 要在整个验证流程中的各验证环节进行传递。一般的做法是将此对象作为方法的一个参数一个个传到各验证环节中去。

这种场景下就很适合采用 ThreadLocal 来实现。一个线程(这个场景下即一个验证流程)要用到一个对象实例( memberType ),而这个对象要在很多地方(每个验证环节)都用到。

看ThreadLocal类的源码可知作为ThreadLocal实例的变量只有 threadLocalHashCode 这一个,而且是final的,用来区分不同的ThreadLocal实例,ThreadLocal类主要是作为工具类来使用。nextHashCode 和HASH_INCREMENT 是ThreadLocal类的静态变量,实际上HASH_INCREMENT是一个常量,表示了连续分配的两个ThreadLocal实例的threadLocalHashCode值的增量,而nextHashCode 的表示了即将分配的下一个ThreadLocal实例的threadLocalHashCode 的值。

分享到:
评论

相关推荐

    正确理解ThreadLocal.pdf

    ### 正确理解ThreadLocal:深入解析其工作原理与应用场景 #### 一、ThreadLocal的基本概念 `ThreadLocal`是Java平台提供的一种线程局部变量的解决方案,它为每一个使用该变量的线程都提供了独立的变量副本,使得每...

    ThreadLocal

    - 内存泄漏:如果线程长时间存活,或者ThreadLocal对象没有被正确清理,可能导致ThreadLocalMap中的引用无法被垃圾回收,从而造成内存泄漏。 - 不适用于跨线程通信:ThreadLocal只保证同一线程内的数据隔离,不同...

    threadLocal

    1. 多线程:理解ThreadLocal的使用必须建立在对多线程的理解基础上,包括线程的创建、执行、同步机制等。 2. 并发编程:ThreadLocal是解决并发问题的一种策略,它提供了一种避免共享状态的方式,减少了锁的使用。 3....

    ThreadLocal的几种误区

    ThreadLocal是Java编程中一种非常特殊的变量类型,它主要...正确使用ThreadLocal可以提高代码的并发性能,而滥用则可能导致难以预料的问题。因此,在使用ThreadLocal时,需要充分考虑其生命周期管理和线程安全问题。

    ThreadLocal 内存泄露的实例分析1

    at 中专门为每一个 web 应用...理解 `ThreadLocal` 的工作原理以及它如何与类加载器交互,是避免此类问题的关键。在实际开发中,应当养成良好的编程习惯,如使用后及时清理 `ThreadLocal` 变量,以防止内存资源的浪费。

    设计模式及ThreadLocal资料

    本资料主要聚焦于两种设计模式以及Java中的ThreadLocal特性。 首先,我们来探讨单例模式。单例模式是一种确保一个类只有一个实例,并提供全局访问点的设计模式。在Java中,通常通过私有构造函数、静态工厂方法或...

    深入理解 Java 之 ThreadLocal 工作原理1

    需要注意的是,尽管ThreadLocal提供了线程局部的变量,但如果不正确地使用,比如在ThreadLocal生命周期结束后没有清理ThreadLocalMap,可能会导致内存泄漏。因此,最佳实践是在不再需要ThreadLocal时调用remove方法...

    Spring事务处理-ThreadLocal的使用

    在实际应用中,理解ThreadLocal在Spring事务处理中的作用有助于优化并发性能和解决多线程环境下的事务问题。例如,如果线程之间需要共享数据,但又不想影响其他线程,ThreadLocal就是一个理想的选择。同时,也要注意...

    java中ThreadLocal类的使用

    - **内存泄漏**:如果`ThreadLocal`没有被正确清理,当线程生命周期结束但引用仍然存在时,可能导致内存泄漏。因此,通常在不再需要`ThreadLocal`时,应该调用`remove`方法。 - **性能影响**:过度使用`ThreadLocal`...

    Java资料-详解ThreadLocal

    让我们通过一个简单的例子来理解`ThreadLocal`的工作机制: ```java public class ThreadLocalExample { private static ThreadLocal<Integer> threadLocal = new ThreadLocal(); public static void main...

    ThreadLocal的原理,源码深度分析及使用.docx

    ThreadLocal 翻译过来就是本地线程,但是直接这么翻译很难理解 ThreadLocal 的作用。如果换一种说法,可以称为线程本地存储。简单来说,就是 ThreadLocal 为共享变量在每个线程中都创建一个副本,每个线程可以访问...

    简单分析Java线程编程中ThreadLocal类的使用共

    理解ThreadLocal的工作原理以及如何正确使用它是Java并发编程的关键。 首先,ThreadLocal类的主要作用是为每个线程创建一个单独的变量副本。这意味着在同一个ThreadLocal变量中,不同的线程可以存储各自独立的值,...

    Python之ThreadLocal共4页.pdf.zip

    Python中的ThreadLocal,全称是`threading.local`,是一个非常重要的并发编程工具。它主要用于在多线程环境中保持线程局部变量,确保每个...正确理解和使用ThreadLocal能够帮助开发者编写出更加健壮和高效的并发程序。

    java并发包源码分析(3)ThreadLocal

    测试用例可以帮助我们更好地理解ThreadLocal的使用和潜在问题: - 创建多个线程,每个线程使用ThreadLocal变量,如果变量引用的是同一个共享对象,修改其中一个线程的变量值,其他线程是否也会看到改变,以此来观察...

    ThreadLocal 线程本地变量 及 源码分析.rar_开发_设计

    ThreadLocal是Java编程语言中的一个类,用于在多线程环境下提供线程局部变量。它为每个线程创建了一个独立的...通过深入理解ThreadLocal的工作原理,可以帮助我们更好地利用这一工具,提高代码的并发性能和可维护性。

    java ThreadLocal使用案例详解

    在本文中,我们将详细介绍Java ThreadLocal的使用案例,并通过一个实际的优化案例,帮助大家理解ThreadLocal的使用。 ThreadLocal的使用场景 在Java多线程编程中,变量的线程安全是一个非常重要的问题。特别是在...

Global site tag (gtag.js) - Google Analytics