ThreadLocal简析

ThreadLocal简析

  • 使用场景
  • 基本使用

使用场景

  1. 一个请求带来的参数需要通过一个个方法传递下去(非常臃肿),可以借助threadLocal成员变量直接获取
  2. 多线程情况下可以保证线程安全

基本使用

public class TestThreadLocal {
    public static final ThreadLocal<Gun> tl = new ThreadLocal<>();

    public static void main(String[] args) {
        tl.set(new Gun()); // 主线程存放值

        new Thread(() -> {
            System.out.println(tl.get()); // 获取不到值,线程隔离
        }).start();
    }
}
public abstract class TestThreadLocal {
    public static final ThreadLocal<Something> SOMETHING = new ThreadLocal<>();
    // 简单使用
    public void handle(SomethingRequest request) {
        setSomething(request.getSomething());
        doHandle(request);
        removeSomething();
    }

    abstract void doHandle(SomethingRequest event);

    protected void setSomething(Something sth) {
        Assert.notNull(sth, "sth");
        SOMETHING.set(sth);
    }

    protected Something getSomething() {
        return SOMETHING.get();
    }

    protected void removeSomething() {
        SOMETHING.remove();
    }
}
  • set方法
 public void set(T value) {
     Thread t = Thread.currentThread();
     ThreadLocalMap map = getMap(t); // 获取当前线程的ThreadLocalMap属性
     if (map != null)
         map.set(this, value); // 将ThreadLocal对象作为key,目标对象作为value存入当前线程的属性中,自然形成线程隔离
     else
         createMap(t, value);
 }

 ThreadLocalMap getMap(Thread t) {
     return t.threadLocals;
 }

/* ThreadLocalMap的set方法 */
  private void set(ThreadLocal<?> key, Object value) {
      Entry[] tab = table; // 一个线程可能会处理多个threadlocal对象
      int len = tab.length;
      int i = key.threadLocalHashCode & (len-1);

      for (Entry e = tab[i];
           e != null;
           e = tab[i = nextIndex(i, len)]) {
          ThreadLocal<?> k = e.get(); // 取得当前的key值
		  
		  // key相同,替换value
          if (k == key) { 
              e.value = value;
              return;
          }

   		  // 清除key为null的entry。key为null,则value永远不会被回收,防止内存泄漏
          if (k == null) { 
              replaceStaleEntry(key, value, i);
              return;
          }
      }

      /* 
       * Entry继承WeekReference,创建虚引用指向key,
       * 当tl指向null时,垃圾回收依然会回收key,否则key将不会被回收,造成内存泄漏
       * 当key被回收时,key为null,则value无法被访问,造成内存泄漏。
       * 所以用完value要调用remove方法
       * 调用set、get方法也会清除key为null的entry
       * */
      tab[i] = new Entry(key, value);
      int sz = ++size;
      if (!cleanSomeSlots(i, sz) && sz >= threshold)
          rehash();
  }
  • Entry
   static class Entry extends WeakReference<ThreadLocal<?>> {
       /** The value associated with this ThreadLocal. */
       Object value;

       Entry(ThreadLocal<?> k, Object v) {
           super(k); // 创建一个虚引用指向k,当k没有其他引用指向时,下一次垃圾回收将被回收
           value = v;
       }
   }
  • get方法
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this); // 根据threadlocal对象获取entry
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value; 返回entry的value
                return result;
            }
        }
        return setInitialValue();
    }

你可能感兴趣的:(线程安全,java)