您的位置:首页 > 编程语言 > Java开发

ThreadLocal的研究_源码分析

2012-09-25 10:28 471 查看
一、ThreadLocal是什么:

       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的源码比较多,大家可以去看一下。

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  thread jdk