ThreadLocal的研究_源码分析
2012-09-25 10:28
471 查看
一、ThreadLocal是什么:
ThreadLocal并不是一个thread,而是相当于thread的一个的局部变量。它只是用来维护本地变量。针对每个线程,提供自己的变量副本,主要是为了避免线程冲突,每个线程维护自己的版本。彼此独立,修改不会影响到对方。
说明:ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
二、下面我们看看jdk1.6源码ThreadLocal的实现:
3个int型变量:
作为实例变量只有threadLocalHashCode一个,nextHashCode 和HASH_INCREMENT 是ThreadLocal类的静态变量,实际上HASH_INCREMENT是一个常量,表示了连续分配的两个ThreadLocal实例的threadLocalHashCode值的增量,而nextHashCode 的表示了即将分配的下一个ThreadLocal实例的threadLocalHashCode 的值。
在创建ThreadLocal实例new ThreadLocal()时从源码中发现并没有操作什么,只对threadLocalHashCode初期化赋值,而且该实例变量是final类型,说明对于同一个ThreadLocal实例threadLocalHashCode值是不变的,用来区分不同的ThreadLocal实例。
几个主要方法:
set():一般要先set 要不然第一次get到的值为null,第一次set时会创建一个ThreadLocalMap对象实例,该map是以ThreadLocal实例为key,要保持的对象value作为值。
get():
initialValue():一般在对ThreadLocal进行实例初始化时要对该方法进行覆盖,否则要先进行set,要不然第一次get值为null。
静态内部类ThreadLocalMap的源码比较多,大家可以去看一下。
ThreadLocal并不是一个thread,而是相当于thread的一个的局部变量。它只是用来维护本地变量。针对每个线程,提供自己的变量副本,主要是为了避免线程冲突,每个线程维护自己的版本。彼此独立,修改不会影响到对方。
说明:ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
二、下面我们看看jdk1.6源码ThreadLocal的实现:
package java.lang; import java.lang.ref.*; import java.util.concurrent.atomic.AtomicInteger; /** * 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. <tt>ThreadLocal</tt> instances are typically private * static fields in classes that wish to associate state with a thread (e.g., * a user ID or Transaction ID). * * <p>For example, the class below generates unique identifiers local to each * thread. * A thread's id is * assigned the first time it invokes <tt>UniqueThreadIdGenerator.getCurrentThreadId()</tt> and remains unchanged on subsequent calls. * <pre> * import java.util.concurrent.atomic.AtomicInteger; * * public class UniqueThreadIdGenerator { * * private static final AtomicInteger uniqueId = new AtomicInteger(0); * * private static final ThreadLocal < Integer > uniqueNum = * new ThreadLocal < Integer > () { * @Override protected Integer initialValue() { * return uniqueId.getAndIncrement(); * } * }; * * public static int getCurrentThreadId() { * return uniqueId.get(); * } * } // UniqueThreadIdGenerator * </pre> * <p>Each thread holds an implicit reference to its copy of a thread-local * variable as long as the thread is alive and the <tt>ThreadLocal</tt> * instance is accessible; after a thread goes away, all of its copies of * thread-local instances are subject to garbage collection (unless other * references to these copies exist). * * @author Josh Bloch and Doug Lea * @version 1.42, 06/23/06 * @since 1.2 */ public class ThreadLocal<T> { /** * ThreadLocals rely on per-thread linear-probe hash maps attached * to each thread (Thread.threadLocals and * inheritableThreadLocals). The ThreadLocal objects act as keys, * searched via threadLocalHashCode. This is a custom hash code * (useful only within ThreadLocalMaps) that eliminates collisions * in the common case where consecutively constructed ThreadLocals * are used by the same threads, while remaining well-behaved in * less common cases. */ private final int threadLocalHashCode = nextHashCode(); /** * The next hash code to be given out. Updated atomically. Starts at * zero. */ private static AtomicInteger nextHashCode = new AtomicInteger(); /** * The difference between successively generated hash codes - turns * implicit sequential thread-local IDs into near-optimally spread * multiplicative hash values for power-of-two-sized tables. */ private static final int HASH_INCREMENT = 0x61c88647; /** * Returns the next hash code. */ private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); } /** * 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 <tt>initialValue</tt> 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 <tt>null</tt>; if the * programmer desires thread-local variables to have an initial * value other than <tt>null</tt>, <tt>ThreadLocal</tt> 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; } /** * Creates a thread local variable. */ public ThreadLocal() { } /** * 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) return (T)e.value; } return 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; } /** * 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); } /** * 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 * <tt>initialValue</tt> method in the current thread. * * @since 1.5 */ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); } /** * 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; } /** * 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 * @param map the map to store. */ void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
3个int型变量:
1.private final int threadLocalHashCode = nextHashCode(); 2.private static int nextHashCode = 0; 3.private static final int HASH_INCREMENT = 0x61c88647;
作为实例变量只有threadLocalHashCode一个,nextHashCode 和HASH_INCREMENT 是ThreadLocal类的静态变量,实际上HASH_INCREMENT是一个常量,表示了连续分配的两个ThreadLocal实例的threadLocalHashCode值的增量,而nextHashCode 的表示了即将分配的下一个ThreadLocal实例的threadLocalHashCode 的值。
在创建ThreadLocal实例new ThreadLocal()时从源码中发现并没有操作什么,只对threadLocalHashCode初期化赋值,而且该实例变量是final类型,说明对于同一个ThreadLocal实例threadLocalHashCode值是不变的,用来区分不同的ThreadLocal实例。
private final int threadLocalHashCode = nextHashCode(); private static synchronized int nextHashCode() { int h = nextHashCode; nextHashCode = h + HASH_INCREMENT; return h; }
几个主要方法:
set():一般要先set 要不然第一次get到的值为null,第一次set时会创建一个ThreadLocalMap对象实例,该map是以ThreadLocal实例为key,要保持的对象value作为值。
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():
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); }
initialValue():一般在对ThreadLocal进行实例初始化时要对该方法进行覆盖,否则要先进行set,要不然第一次get值为null。
protected T initialValue() { return null; }
静态内部类ThreadLocalMap的源码比较多,大家可以去看一下。
相关文章推荐
- PHP内核研究: PHP源码目录分析
- 【Java8源码分析】线程-ThreadLocal的全面剖析
- vnc-4.0-winsrc版本之winvnc工程分析_源码研究
- SpringMVC关于json、xml自动转换的原理研究[附带源码分析]
- spark机器学习算法研究和源码分析
- 深入研究Spring-IoC:源码分析依赖注入
- ThreadLocal应用场景以及源码分析
- ThreadLocal 源码分析
- SpringMVC关于json、xml自动转换的原理研究[附带源码分析]
- 并发编程(四):ThreadLocal从源码分析总结到内存泄漏
- ThreadLocal源码分析
- 在江北研究jsunpackn(源码分析)
- Object源码研究2——getClass()方法分析
- ThreadLocal源码分析与使用场景
- java-----ThreadLocal源码分析
- 小米开源文件管理器MiCodeFileExplorer-源码研究(9)-入口分析
- Java并发编程系列(六)---- ThreadLocal使用及源码分析
- ThreadLocal与WeakReference 源码分析
- ThreadLocal 从源码角度简单分析
- muduo源码分析:线程特定/私有数据类ThreadLocal