ThreadLocal的用法与源码分析

来源:互联网 发布:科比81数据 编辑:程序博客网 时间:2024/05/05 11:35
   目   录:
  1. 深入理解ThreadLocal
  2. ThreadLocal的基本用法
  3. ThreadLocal源码分析
  4. ThreadLocal使用场景
  5. 使用ThreadLocal应注意什么
 
一:深入理解ThreadLocal
         ThreadLocal,很多地方叫做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多。可能很多朋友都知道ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
       ThreadLocal 位于java.lang包下, 该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get  set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
      当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
    二:ThreadLocal的基本用法
         ThreadLocal包含4个基本方法: get()、set()、initialValue()、remove() ;
 T
get()           返回此线程局部变量的当前线程副本中的值。
protected  T
initialValue()           返回此线程局部变量的当前线程的“初始值”。
 void
remove()           移除此线程局部变量当前线程的值。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
 void
set(T value)           将此线程局部变量的当前线程副本中的值设置为指定值。
 
三:ThreadLocal的源码分析
 
  1. /** 
  2.  * Returns the value in the current thread's copy of this 
  3.  * thread-local variable.  If the variable has no value for the 
  4.  * current thread, it is first initialized to the value returned 
  5.  * by an invocation of the {@link #initialValue} method. 
  6.  * 
  7.  * @return the current thread's value of this thread-local 
  8.  */  
  9. public T get() {  
  10.     Thread t = Thread.currentThread();  //得到当前线程
  11.     ThreadLocalMap map = getMap(t);  //获取当前线程相关的ThreadLocalMap
  12.     if (map != null) {  
  13.         ThreadLocalMap.Entry e = map.getEntry(this);  //
  14.         if (e != null)  
  15.             return (T)e.value;  
  16.     }  
  17.     return setInitialValue();  //如果获取不到当前线程相关ThreadLocalMap对象,则调用“初始值”方法。开发者可重写initialValue();
  18. }
 
     获取一个和当前线程相关的ThreadLocalMap
  1. /** 
  2.  * Get the map associated with a ThreadLocal. Overridden in 
  3.  * InheritableThreadLocal. 
  4.  * 
  5.  * @param  t the current thread 
  6.  * @return the map 
  7.  */  
  8. ThreadLocalMap getMap(Thread t) {  
  9.     return t.threadLocals;  
  10. }  
 
 
  1. /** 
  2.     * Sets the current thread's copy of this thread-local variable 
  3.     * to the specified value.  Most subclasses will have no need to 
  4.     * override this method, relying solely on the {@link #initialValue} 
  5.     * method to set the values of thread-locals. 
  6.     * 
  7.     * @param value the value to be stored in the current thread's copy of 
  8.     *        this thread-local. 
  9.     */  
  10.    public void set(T value) {  
  11.        Thread t = Thread.currentThread();  
  12.        ThreadLocalMap map = getMap(t);  
  13.        if (map != null)  
  14.            map.set(this, value);  //将该变量赋值到ThreadLocal对象。
  15.        else  
  16.            createMap(t, value);  //如果该ThreaLocal为空,则创建该对象并赋值该变量
  17.    } 
  18.  
 
    创建ThreadLocal对象
 
  1. /** 
  2.  * Create the map associated with a ThreadLocal. Overridden in 
  3.  * InheritableThreadLocal. 
  4.  * 
  5.  * @param t the current thread 
  6.  * @param firstValue value for the initial entry of the map 
  7.  * @param map the map to store. 
  8.  */  
  9. void createMap(Thread t, T firstValue) {  
  10.     t.threadLocals = new ThreadLocalMap(this, firstValue);  
           
             setInitialValue() 方法 ,这里很容易理解
  1. /** 
  2.     * Variant of set() to establish initialValue. Used instead 
  3.     * of set() in case user has overridden the set() method. 
  4.     * 
  5.     * @return the initial value 
  6.     */  
  7.    private T setInitialValue() {  
  8.        T value = initialValue();  
  9.        Thread t = Thread.currentThread();  
  10.        ThreadLocalMap map = getMap(t);  
  11.        if (map != null)  
  12.            map.set(this, value);  
  13.        else  
  14.            createMap(t, value);  
  15.        return value;  
  16.    } 
 
 
  1.  
  2. // remove方法
  3.  
  4. public void remove()  {    ThreadLocalMap localThreadLocalMap = getMap(Thread.currentThread());    if (localThreadLocalMap != null)      localThreadLocalMap.remove(this);  }
 
四:ThreadLocal的使用场景
 
ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量),这样当然不需要对多个线程进行同步了。如果你需要进行多个线程之间进行通信,则使用同步机制;如果需要隔离多个线程之间的共享冲突,就可以使用ThreadLocal。
 
五:使用ThreadLocal 应注意什么
 1.使用ThreadLocal时,应先使用set方法对其"赋值"操作,如果未先进行赋值,会报空指针异常(如果未重写initialValue()方法)。或者重写initialValue()方法!
 2.使用完ThreadLocal后,建议调用remove()通知GC回收该对象,勿直接将ThreadLocal置为null,否则可能导致OutOfMemoryError异常。
3.还有一点就是,ThreadLocalMap存储的键值对中的键是this对象指向的ThreadLocal对象,而值就是你所设置的对象了。
 
 
 
0 0
原创粉丝点击