• ThreadLocal可以用来存储当前线程的一些数据,每一个Thread对象中,都有一个ThreadLocalMap属性,key为ThreadLocal,vaule为Oject数据,ThreadLocal类中有一个静态内部类ThreadLocalMap,由ThreadLocal和value组成一个弱引用的Entry对象

  • set的时候,先获取当前线程对象,将当前ThreadLocal作为key,值为value封装成一个ThreadLocalMap,然后设置进去当前线程Thread中的ThreadLocalMap中

    • public void set(T value) {
          Thread t = Thread.currentThread();
          ThreadLocalMap map = getMap(t);
          if (map != null)
          map.set(this, value);
          else
          createMap(t, value);
      }
      
      void createMap(Thread t, T firstValue) {
      	t.threadLocals = new ThreadLocalMap(this, firstValue);
      }
      
  • get的时候,将当前ThreadLocal对象作为key,从当前Thread对象ThreadLocalMap中的获取到值

    • public T get() {
          Thread t = Thread.currentThread();
          ThreadLocalMap map = getMap(t);
          if (map != null) {
              ThreadLocalMap.Entry e = map.getEntry(this);
              if (e != null) {
                  @SuppressWarnings("unchecked")
                  T result = (T)e.value;
                  return result;
              }
          }
          return setInitialValue();
      }
      
      ThreadLocalMap getMap(Thread t) {
          return t.threadLocals;
      }
      
  • 内存泄漏的情况

    • 线程池中的线程一般都是重复利用的,那么该线程中的ThreadLocalMap也一直存在,ThreadLocalMap中的ThreadLocal对象也会一直存在并且不断的增加(用完的不会清楚掉),所以可能会泄露。
    • 每次使用完ThreadLocal都要调用remove()方法清除数据
    • 使用private static
  • 使用场景

    • public class Person {
          private ThreadLocal<String> name = new ThreadLocal<>();
          private ThreadLocal<String> location = new ThreadLocal<>();
      
          public String getName() {
              return this.name.get();
          }
      
          public  void setName(String name) {
              this.name.set(name);
          }
      
          public  String getLocation() {
              return this.location.get();
          }
      
          public void setLocation(String location) {
              this.location.set(location);
          }
      }
      
      
      vpublic class ThreadUseTest {
      
          public static void main(String[] args) {
              Person person = new Person();
      
              new Thread(new Runnable() {
                  @Override
                  public void run() {
                      person.setLocation("guangdong");
                      person.setName("johnbarrowman");
                      try {
                          Thread.sleep(3000);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(person.getLocation()+ person.getName());
                  }
              }).start();
      
              new Thread(new Runnable() {
                  @Override
                  public void run() {
                      person.setLocation("guangdong1");
                      person.setName("johnbarrowman1");
                      try {
                          Thread.sleep(3000);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(person.getLocation()+ person.getName());
                  }
              }).start();
          }
      }
      
      

Q.E.D.