ThreadLocal、ThreadLocalMap、InheritableThreadLocal源码解读

ThreadLocal、ThreadLocalMap、InheritableThreadLocal源码解读

    • 1.ThreadLocal解读
      • 1-1.ThreadLocal代码小示例
      • 1-2.get方法源码
      • 1-3.setInitialValue()方法源码
    • 2.ThreadLocalMap解读
      • 2-1.Thread的ThreadLocalMap
      • 2-2.ThreadLocalMap源码
    • 3.InheritableThreadLocal解读

1.ThreadLocal解读

ThreadLocal这个类提供“thread-local”的一些变量。这些变量与普通变量不同,每个的线程可以通过各自的get或set方法对这些的独立的初始化的变量的副本(copy)进行操作。ThreadLocal的实例在类里面通常是一个私有静态字段(private static field),通过这个方式来将状态与线程相关联(比如,user ID或Transcation ID)。

1-1.ThreadLocal代码小示例

下面这个代码示例中,ThreadId类生成每个线程的本地唯一标识符。线程的id在第一次调用ThreadId.get()时分配,并在后续调用中保持不变。

  import java.util.concurrent.atomic.AtomicInteger;
 
  public class ThreadId {
      // Atomic integer containing the next thread ID to be assigned
      private static final AtomicInteger nextId = new AtomicInteger(0);
 
      // Thread local variable containing each thread's ID
      private static final ThreadLocal<Integer> threadId =
          new ThreadLocal<Integer>() {
              @Override protected Integer initialValue() {
                  return nextId.getAndIncrement();
          }
      };
 
      // Returns the current thread's unique ID, assigning it if necessary
      public static int get() {
          return threadId.get();
      }
  }

也就是说,只要线程处于alive状态并且ThreadLocal的实例可访问,那么每个线程都持有对它自己的“thread-local”变量的副本的隐式引用。若线程消失,其“thread-local”实例的所有变量的副本都会垃圾回收(除非存在对这些变量的副本的其他引用)。

1-2.get方法源码

public class ThreadLocal<T> {
    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();
        }
  
  	...
}

get()方法返回当前线程“thread-local”变量的副本中的值。如果变量没有当前线程的值,则优先初始化的方式是调用initialValue方法得到初始值。

1-3.setInitialValue()方法源码

public class ThreadLocal<T> {
		/**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
  
  	...
}

set()的变体用于建立initialValue,通常会override这个set()方法。

2.ThreadLocalMap解读

ThreadLocalMap是一个自定义的哈希的map,仅适用维护线程local值。不会在类ThreadLocal外部导出任何操作。 该类是package private的,允许在类Thread中声明字段。

2-1.Thread的ThreadLocalMap

public
class Thread implements Runnable {
    
    //线程相关的`ThreadLocal`的值。这个map由类`ThreadLocal`维护。
    
    /* ThreadLocal values pertaining to this thread. This map is maintained
    * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

  ...
}

2-2.ThreadLocalMap源码

针对处理非常多且长期存在的用法哈希表的entries对keys使用弱引用(WeakReference)。但是,由于不使用引用队列,因此仅当表开始空间不足,才能保证删除过时的entries。

ThreadLocalMap的Entry

public class ThreadLocal<T> {

  	static class ThreadLocalMap {

      
      static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
          super(k);
          value = v;
        }
      }

  		...
        
		}
  	...
}

ThreadLocalMap的table

public class ThreadLocal<T> {

  	static class ThreadLocalMap {

      /** The table, resized as necessary. table.length MUST always be a power of two.*/
      private Entry[] table;
  		...
        
		}
  	...
}

哈希的map的entries继承了WeakReference,使用其主要的ref字段(指T referent)作为key(始终是一个ThreadLocal对象)。

注意,空键(即entry.get() == null)表示不再引用该键,因此可以从表中删除这个entry。这类entry被称为过时的entry(stale entries)。

3.InheritableThreadLocal解读

InheritableThreadLocal继承了类ThreadLocal,可提供从父线程到子线程的值的继承。

当创建子线程时,父线程所具有的全部的可以继承的“thread-local”的变量的值可被子线程接收,作为子线程的初始值。

通常,子线程的值和父线程的值是相同的,但是可以通过重写类InheritableThreadLocal中的方法chileValue()方法,使子线程的值是父线程值的任意自定义函数的映射值。

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
    
    protected T childValue(T parentValue) {
        return parentValue;
    }
  	...
}

当创建子线程时,变量中维护的每个线程的属性(比如,user ID或Transcation ID)必须传输到子线程。注意,可继承的“thread-local”变量优先级高于普通“thread-local”变量。

你可能感兴趣的:(java)