`

ThreadLocal总结

 
阅读更多

原文: ThreadLocal-分析-总结  网上虽然很多关于ThreadLocal , 但是这篇文章,从

源码角度进行剖析 ,让你不得不信服,Thanks!

 

以前,对ThreadLocal 错误的理解:

 它内部维护了一个map,然后,这个map的key是本地线程的标志,value则是线程不安全的对象

 其实,不是这样的:

 1. ThreadLocal 中有个内部类,ThreadLocalMap ,但是它并没有map这个成员变量,它只是对map进行操作!

      map则是存在于各个线程中的。查看Thread的源代码就可以看到每个Thread都有一个ThreadLocal的成员变量!

 2.   ThreadLocal中的key不是线程的标志,而是TheadLocal这个对象,map不是在TheadLocal中!!!

 3. 每个线程中都有一个ThreadLocalMap , map的key为ThreadLocal对象,这样不管你有多少个ThreadLocal , 线程中

     都会存储你相应的值! 

 4. 这样看的话,ThreadLocal 的作用,就会使某个线程一直占用着某个资源!并不是数据的共享!

     当然,如果你set的对象是一个线程间共享的对象,那就另当别论了。比如 只要一个Node n , 而所有线程都是set的这个!

    不过,这就与ThreadLocal的使用场景不同!它里面存放是不同的对象!每个线程都是不同的!

 5.将map绑定到当前线程的好处:

     当前线程销毁的时候,相应的map也销毁了,这里,要注意,线程池的情况!!!

     各线程访问的map是各自不同的map,所以不需要同步,速度会快些;而如果把所有线程要用的对象都放到一个静态map中的话 多线程并发访问需要进行同步。

 5.ThreadLocal 与 synchronized的区别:

ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。

Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。

 

 图片出处: http://www.cnblogs.com/onlywujun/p/3524675.html 

 

 

下面是原文:

ThreadLocal<T>类在Spring,Hibernate等框架中起到了很大的作用,对于其工作原理,很多网上的文章分析的不够彻底,甚至有些误解。

首先,为了解释ThreadLocal类的工作原理,必须同时介绍与其工作甚密的其他几个类(内部类)

1.ThreadLocalMap

2.Thread

可能有人会觉得Thread与ThreadLocal有什么关系,其实真正的奥秘就在Thread类中的一行:

ThreadLocal.ThreadLocalMap threadLocals = null;  

 

   其中ThreadLocalMap的定义是在ThreadLocal类中,真正的引用却是在Thread类中

   那么ThreadLocalMap究竟是什么呢?

 

可以看到这个类应该是一个Map,JDK的解释是

ThreadLocalMap is a customized hash map suitable only for maintaining thread local values

 

接下来的重点是ThreadLocalMap中用于存储数据的entry

 

static class Entry extends WeakReference<ThreadLocal> {  
            /** The value associated with this ThreadLocal. */  
            Object value;  
  
            Entry(ThreadLocal k, Object v) {  
                super(k);  
                value = v;  
            }  
        } 

 

从中我们可以发现这个Map的key是ThreadLocal变量,value为用户的值,并不是网上大多数的列子key是线程的名字或者标识

到这里,我们就可以理解ThreadLocal究竟是如何工作的了

1.Thread类中有一个成员变量叫做ThreadLocalMap,它是一个Map,他的Key是ThreadLocal类

2.每个线程拥有自己的申明为ThreadLocal类型的变量,所以这个类的名字叫'ThreadLocal':线程自己的(变量)

3.此变量生命周期是由该线程决定的,开始于第一次初始(get或者set方法)

4.由ThreadLocal的工作原理决定了:每个线程独自拥有一个变量,并非共享或者拷贝

 

/** 
 * @author mxdba 
 * 
 */  
public class ThreadLocalSample {  
  
    public static void main(String[] args) {  
        ThreadTest test1 = new ThreadTest(10);  
        ThreadTest test2 = new ThreadTest(20);  
        test1.start();  
        test2.start();  
    }  
  
}  
  
/** 
 * 此线程有两个ThreadLocal变量,但是由于ThreadLocal是延迟初始的, 
 * 所以在debug时可以看到线程名为“线程20”的线程的ThreadLocalMap中没有thLcal2这个entry 
 * @author mxdba 
 *  
 */  
class ThreadTest extends Thread {  
      
    public static ThreadLocal<Integer> thLocal = new ThreadLocal<Integer>();  
    public static ThreadLocal<String> thLocal2 = new ThreadLocal<String>();  
      
    public Integer num;  
      
      
      
    public ThreadTest(Integer num) {  
        super("线程" + num);  
        this.num = num;  
    }  
  
    @Override  
    public void run() {  
        Integer n = thLocal.get();  
        if(num != 20) {  
            String s = thLocal2.get();  
        }  
              
        if(n == null) {  
            thLocal.set(num);  
        }  
        System.out.println(thLocal.get());  
    }  
      
}   

 

接下来分析一下源码,就更加清楚了

 

/**  
 * 关键方法,返回当前Thread的ThreadLocalMap  
 * [[[每个Thread返回各自的ThreadLocalMap,所以各个线程中的ThreadLocal均为独立的]]]  
 */  
ThreadLocalMap getMap(Thread t) {  
        return t.threadLocals;  
    }  

 

 get方法源代码:

  

public T get() {  
        Thread t = Thread.currentThread();  
        /**  
         * 得到当前线程的ThreadLocalMap  
         */  
        ThreadLocalMap map = getMap(t);  
        if (map != null) {  
            /**  
             * 在此线程的ThreadLocalMap中查找key为当前ThreadLocal对象的entry  
             */  
            ThreadLocalMap.Entry e = map.getEntry(this);  
            if (e != null)  
                return (T)e.value;  
        }  
        return setInitialValue();  
    }  

  

    初始化代码:

   

private T setInitialValue() {  
        /**  
         * 默认返回null,这个方法为protected可以继承  
         */  
        T value = initialValue();  
        Thread t = Thread.currentThread();  
        ThreadLocalMap map = getMap(t);  
        if (map != null)  
            map.set(this, value);  
        else  
            /**  
             * 初次创建  
             */  
            createMap(t, value);  
        return value;  
    }  

  

 

/** 
 * 给当前thread初始ThreadlocalMap 
 */  
void createMap(Thread t, T firstValue) {  
        t.threadLocals = new ThreadLocalMap(this, firstValue);  
    }  

  

 

 

通过上边的分析,我们发现,ThreadLocal类的使用虽然是用来解决多线程的问题的,但是还是有很明显的针对性

 使用场景:

1.最明显的,ThreadLoacl变量的活动范围为某线程,并且我的理解是该线程“专有的,独自霸占”,对该变量的所有操作均有该线程完成!也就是说,ThreadLocal不是用来解决共享,竞争问题的。典型的应用莫过于Spring,Hibernate等框架中对于多线程的处理了

 

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;    
}    

 

 这段代码,每个线程有自己的ThreadLocalMap,每个ThreadLocalMap中根据需要初始加载threadSession,这样的好处就是介于singleton与prototype之间,应用singleton无法解决线程,应用prototype开销又太大,有了ThreadLocal之后就好了,对于需要线程“霸占”的变量用ThreadLocal,而该类实例的方法均可以共享。(例如,某个成员变量,我们要独占,就可以用ThreadLocal , 这样看的话,ThreadLocal类,不就可以看成

 一个可以实现独占功能类!)

  

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

 

2、存放当前session用户:quake want的jert
3、存放一些context变量,比如webwork的ActionContext

 

3.关于内存泄漏:

虽然ThreadLocalMap已经使用了weakReference,但是还是建议能够显示的使用remove方法。

分享到:
评论

相关推荐

    ThreadLocal 内存泄露的实例分析1

    总结:`ThreadLocal` 是一个强大的工具,但在使用时必须谨慎,尤其是在多线程环境中,如 Tomcat 这样的 Web 容器。如果不正确地管理 `ThreadLocal` 的生命周期,可能导致类加载器级别的内存泄漏。理解 `ThreadLocal`...

    正确理解ThreadLocal.pdf

    #### 六、总结 `ThreadLocal`是一种强大的工具,它简化了多线程编程中对线程局部数据的管理,提高了代码的可读性和可维护性。然而,不当的使用也可能导致内存泄漏和其他潜在问题。因此,在使用`ThreadLocal`时,...

    java事务 - threadlocal

    总结一下,Java事务和ThreadLocal都是Java多线程编程中不可或缺的工具。事务用于保证数据库操作的原子性和一致性,ThreadLocal则为每个线程提供了独立的数据空间,避免了线程间的数据冲突。理解并熟练运用这两个概念...

    java中ThreadLocal详解

    ### 六、总结 `ThreadLocal`是Java中用于解决线程间数据隔离的有效工具。通过为每个线程创建独立的变量副本,它不仅简化了代码,还提高了程序的可维护性和安全性。需要注意的是,尽管使用了弱引用来避免内存泄漏,...

    设计模式及ThreadLocal资料

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

    使用ThreadLocal管理“session”数据

    总结,ThreadLocal是Java中处理线程局部数据的利器,特别适用于需要线程隔离的场景,如Web应用中的session管理。通过合理使用ThreadLocal,可以提升程序的并发性能并保证数据安全性。但同时,需要注意内存管理和避免...

    java中ThreadLocal类的使用

    总结,`ThreadLocal`是Java中用于实现线程局部变量的工具,它提供了一种简单的方式在多线程环境下隔离数据,避免了传统的同步机制。但是,使用时需注意其潜在的内存泄漏风险和对代码可读性的影响,合理地选择使用...

    从ThreadLocal的使用到Spring的事务管理

    总结起来,ThreadLocal和Spring的事务管理是Java开发中解决并发问题和保证数据一致性的重要手段。熟练掌握这两个概念,有助于构建稳定、高效的分布式系统。通过深入学习源码和实际应用,我们可以更好地理解其工作...

    ThreadLocal和事务

    总结来说,这个小型练习展示了如何在Java Web应用中有效地结合c3p0数据源、ThreadLocal和事务管理,以实现安全、高效的转账操作。ThreadLocal提供了线程安全的变量管理,c3p0优化了数据库连接的使用,而事务则保证了...

    JAVA ThreadLocal类深入

    总结来说,ThreadLocal是Java中解决多线程数据隔离问题的有效工具,通过为每个线程提供独立的变量副本,它能够在不引入复杂同步机制的情况下,实现线程安全的代码编写。在设计需要线程安全的类或组件时,ThreadLocal...

    理解threadlocal

    #### 六、总结 通过以上分析,我们可以看到`ThreadLocal`为多线程环境下的编程提供了一种简洁优雅的解决方案。它不仅能够避免复杂的同步问题,还能有效地管理线程间的变量隔离。理解`ThreadLocal`的工作原理及其...

    Java并发编程学习之ThreadLocal源码详析

    ThreadLocal的实现原理可以总结为:每个线程都有一个自己的ThreadLocalMap,用于存放线程的本地变量;ThreadLocal的set、get、remove方法都是基于ThreadLocalMap的操作。 ThreadLocal的优点是可以解决多线程访问...

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

    总结起来,ThreadLocal的核心是通过每个线程内部的ThreadLocalMap来实现变量的线程隔离。它简化了线程安全的处理,允许在多线程环境中为每个线程提供独立的变量副本,而无需同步。理解和掌握ThreadLocal的工作原理...

    JAVA并发-自问自答学ThreadLocal.pdf

    总结起来,ThreadLocal是Java中实现线程局部变量的一种机制,它使得线程间的数据独立,避免了并发编程中的数据共享问题,简化了多线程环境下的状态管理。然而,使用ThreadLocal时必须注意内存管理和对象的生命周期,...

    ThreadLocal:如何优雅的解决SimpleDateFormat多线程安全问题

    目录SimpleDateFormat诡异bug复现SimpleDateFormat诡异bug字符串日期转Date日期(parse)Date日期转String类型(format)SimpleDateFormat出现...注意事项使用ThreadLocal解决SimpleDateFormat线程安全问题总结...

    Hibernager_Session_Manager_ThreadLocal

    总结起来,"Hibernage_Session_Manager_ThreadLocal"是一个关于使用ThreadLocal在多线程环境中优化Hibernate Session管理的技术实践,通过这种方式可以提升应用程序的性能和安全性。`HibernateUtil.java`是实现这一...

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

    总结来说,Java线程编程中的ThreadLocal类提供了一种高效、便捷的方式来实现线程间的隔离数据,但同时也需要开发者注意其潜在的内存泄漏风险。正确理解和使用ThreadLocal,能够帮助我们编写出更加健壮、高效的并发...

    ThreadLocal,你真的了解吗?

    总结,ThreadLocal 提供了一种线程隔离的变量存储方式,而 Java 中的四种引用类型则帮助我们更好地控制对象的生命周期和内存管理,理解这些概念对于理解和使用 ThreadLocal 至关重要,同时也是面试中经常考察的知识...

Global site tag (gtag.js) - Google Analytics