java ThreadLocal使用
Posted kingsonfu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java ThreadLocal使用相关的知识,希望对你有一定的参考价值。
1、源码分析
此处以JDK1.8版本分析
1.1 set方法
/** * Sets the current thread‘s copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the @link #initialValue * method to set the values of thread-locals. * * @param value the value to be stored in the current thread‘s copy of * this thread-local. */ public void set(T value) Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value);
此处的ThreadLocalMap为ThreadLocal的一个内部类,用Entry来存储要设置的值。如下
static class ThreadLocalMap /** * 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;
看下getMap()方法,用于返回当前ThreadLocal维护的ThreadLocalMap对象,如下
/** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t) return t.threadLocals;
此处的t.threadLocals为当前Thread维护的ThreadLocalMap对象
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
再看下createMap()方法,用于为当前Thread没有ThreadLocalMap时新建一个ThreadLocalMap,如下
/** * Create the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @param firstValue value for the initial entry of the map */ void createMap(Thread t, T firstValue) t.threadLocals = new ThreadLocalMap(this, firstValue);
从源码中可以看出set方法过程:获取当前线程,并作为句柄去获取ThreadLocalMap,如果ThreadLocalMap存在,则以当前ThreadLocal对象为key,传入的对象为value进行存储。否则新建一个和当前线程相关联的ThreadLocalMap来存储。
1.2 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); if (map != null) ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) @SuppressWarnings("unchecked") T result = (T)e.value; return result; return setInitialValue();
从源码可以看出也是以当前线程为句柄获取ThreadLocalMap对象,如果存在则返回当前线程的ThreadLocal为key对应的值,否则设置初始值setInitialValue
/** * 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;
其中initialValue返回null
/** * Returns the current thread‘s "initial value" for this * thread-local variable. This method will be invoked the first * time a thread accesses the variable with the @link #get * method, unless the thread previously invoked the @link #set * method, in which case the @code initialValue method will not * be invoked for the thread. Normally, this method is invoked at * most once per thread, but it may be invoked again in case of * subsequent invocations of @link #remove followed by @link #get. * * <p>This implementation simply returns @code null; if the * programmer desires thread-local variables to have an initial * value other than @code null, @code ThreadLocal must be * subclassed, and this method overridden. Typically, an * anonymous inner class will be used. * * @return the initial value for this thread-local */ protected T initialValue() return null;
1.3 remove()方法
/** * Removes the current thread‘s value for this thread-local * variable. If this thread-local variable is subsequently * @linkplain #get read by the current thread, its value will be * reinitialized by invoking its @link #initialValue method, * unless its value is @linkplain #set set by the current thread * in the interim. This may result in multiple invocations of the * @code initialValue method in the current thread. * * @since 1.5 */ public void remove() ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this);
从源码可以很容易看出remove的作用过程,不做详细分析。为了避免内存泄漏问题,尽量在当前线程处理完之后手动进行remove操作。
2、总结
从上面的源码可以看出ThreadLocal设置的值和线程相关,可以理解为是线程的私有的访问区域,其他线程无法访问,实现了“数据隔离”效果。和解决并发问题和共享变量无关
每个Thread都维护者一个ThreadLocalMap的引用。
以上是关于java ThreadLocal使用的主要内容,如果未能解决你的问题,请参考以下文章