ThreadLocal可以在线程内的定义一个变量,该变量是在该线程内的,所以是线程安全的。
(This class provides thread-local variables. These variables differ from * their normal counterparts in that each thread that accesses one (via its* <tt>get</tt> or <tt>set</tt> method) has its own, independently initialized
* copy of the variable.)
ThreadLocal类怎么使用:
public class ThreadLocalTest { public class ThreadLocalVariableHolder { private static ThreadLocal<Integer> value = new ThreadLocal<Integer>(){ private Random rand = new Random(47); //覆盖父类的initialValue方法,初始化线程内的变量 @Override protected Integer initialValue() { return rand.nextInt(10000); } }; public static void increment(){ value.set(value.get() + 1); } public static int get(){ return value.get(); } }
ThreadLocal类实现原理:
ThreadLocal类实现线程原理是,每个线程中都有一个ThreadLocalMap存储该线程所有的ThreadLocal变量。
Thread: /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocalMap的key是ThreadLocal,value是线程存储对应ThreadLocal的变量。这里特别注意,Entry为一个WeakReference,这样HashMap就不回溢出了。
/** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference<ThreadLocal> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } }
ThreadLocal的get方法
/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local */ public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t);//获取线程内的ThreadLocalMap if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); }