zoukankan      html  css  js  c++  java
  • ThreadLocal

    1.ThreadLocal干什么的?
          我们知道,在多线程程序中,同一个线程在某个时间段只能处理一个任务.我们希望在这个时间段内,任务的某些变量能够和处理它的线程进行绑定,在任务需要使用这个变量的时候,这个变量能够方便的从线程中取出来.ThreadLocal能很好的满足这个需求,用ThreadLocal变量的程序看起来也会简洁很多,因为减少了变量在程序中的传递.
     
    2.ThreadLocal的原理是怎么样的?
        每个运行的线程都会有一个类型为ThreadLocal.ThreadLocalMap的map,这个map就是用来存储与这个线程绑定的变量,map的key就是ThreadLocal对象,value就是线程正在执行的任务中的某个变量的包装类Entry.
     
    3. ThreadLocal保存变量的生命周期是怎么样的?
        ThreadLocal保存变量的生命周期 <=任务的生命周期<=线程的生命周期
     
    4. ThreadLocal的应用及源代码解析    
    Java代码  收藏代码
    1. public class UserContextHolder {  
    2.   private static final ThreadLocal<User>  userThreadLocal = new ThreadLocal<User>();  
    3.     
    4.   public static  User get(){  
    5.       return userThreadLocal.get();  
    6.   }  
    7.     
    8.   public static void set(User user){  
    9.        userThreadLocal.set(user);  
    10.   }  
    11. }  
        
    UserContextHolder的get方法最终会调用ThreadLocal的get方法,ThreadLocal的get方法如下:
    Java代码  收藏代码
    1. public T get() {  
    2.     Thread t = Thread.currentThread();//取得当前的thread  
    3.     ThreadLocalMap map = getMap(t);//取得当前thread的ThreadLocalMap对象  
    4.     if (map != null) { //返回key为当前ThreadLocal的value值  
    5.         ThreadLocalMap.Entry e = map.getEntry(this);  
    6.         if (e != null)  
    7.             return (T)e.value;  
    8.     }  
    9.     return setInitialValue();//返回默认值null  
    10. }  
     
     ThreadLocalMap 的key为当前的Threadlocal对象,Threadlocal对象的hashcode实现如下:
    Java代码  收藏代码
    1. private final int threadLocalHashCode = nextHashCode();  
    2.   
    3. private static AtomicInteger nextHashCode = new AtomicInteger();  
    4.   
    5. private static final int HASH_INCREMENT = 0x61c88647;  
    6.     
    7. private static int nextHashCode() {  
    8.     return nextHashCode.getAndAdd(HASH_INCREMENT);   
    9.     }  
      threadLocalHashCode的值即为 Threadlocal对象的hashcode值,从上面可以知道,
       Threadlocal对象的hashcode值是递增的,是HASH_INCREMENT的N倍.这个也和以前遇到的hashcode的生成方式不一样
     
      UserContextHolder的set方法最终会调用ThreadLocal的set方法,ThreadLocal的set方法如下:
    Java代码  收藏代码
    1. public void set(T value) {  
    2.     Thread t = Thread.currentThread();  
    3.     ThreadLocalMap map = getMap(t);//取得当前线程对应的ThreadLocalMap   
    4.     if (map != null)  //ThreadLocalMap不空,把value以当前ThreadLocal为key放到ThreadLocalMap 中  
    5.         map.set(this, value);  
    6.     else  //创建一个ThreadLocalMap.并把value放到ThreadLocalMap中  
    7.         createMap(t, value);  
    8. }  
         
       ThreadLocal还有一个常用的方法remove,如下:
    Java代码  收藏代码
    1. public void remove() {  
    2.     ThreadLocalMap m = getMap(Thread.currentThread());  
    3.     if (m != null)  
    4.         m.remove(this);  
    5. }  
     
    Java代码  收藏代码
    1.    /** 
    2.       * Remove the entry for key. 
    3.       */  
    4.      private void remove(ThreadLocal key) {  
    5.          Entry[] tab = table;  
    6.          int len = tab.length;  
    7.          int i = key.threadLocalHashCode & (len-1);  
    8.          for (Entry e = tab[i];  
    9. e != null;  
    10. e = tab[i = nextIndex(i, len)]) {  
    11.              if (e.get() == key) {  
    12.                  e.clear();  
    13.                  expungeStaleEntry(i);  
    14.                  return;  
    15.              }  
    16.          }  
    17.      }  
         从上可以看到,调用ThreadLocal的remove方法后,当前存放的Entry会从map中清除
     
    5.ThreadLocal的set(null)和remove方法有什么区别?
        set(null)把当前的ThreadLocal为key的值设为了空,避免线程下次再执行其他任务时被使用,但此时这个key对应的Entry值还在,只是Entry.value=null
          remove方法会把这个key对应Entry的值设为空
          所以从重用和效率的角度来说,set(null)的性能优于remove,在实际的项目中推荐使用set(null)来回收ThreadLocal设置的值.
     
    6. 为什么ThreadLocalMap的Entry是一个weakReference?     
         使用weakReference,能够在ThreadLocal失去强引用的时候,ThreadLocal对应的Entry能够在下次gc时被回收,回收后的空间能够得到复用,在一定程度下能够避免内存泄露.
     
    7.使用ThreadLocal应该注意什么?
         在使用ThreadLocal对象,尽量使用static,不然会使线程的ThreadLocalMap产生太多Entry,从而造成内存泄露
  • 相关阅读:
    spring框架学习笔记(七)
    spring框架学习笔记(六)
    spring框架学习笔记(五)
    spring框架学习笔记(四)
    spring框架学习笔记(三)
    leetcode 147. Insertion Sort List ----- java
    leetcode 146. LRU Cache ----- java
    leetcode 145. Binary Tree Postorder Traversal ----- java
    leetcode 144. Binary Tree Preorder Traversal ----- java
    leetcode 143. Reorder List ----- java
  • 原文地址:https://www.cnblogs.com/inyu/p/13659094.html
Copyright © 2011-2022 走看看