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

ThreadLocal认知学习

2016-04-11 11:11 441 查看

ThreadLocal认知学习

概述

java doc介绍

This class provides thread-local variables. These variables differ fromtheir normal counterparts in that each thread that accesses one (via itsget or set method) has its own, independently initializedcopy of the variable. ThreadLocal instances are typically privatestatic fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).

网上总结

ThreadLocal类的使用虽然是用来解决多线程的问题,ThreadLocal不是用来解决共享,竞争问题的。

ThreadLocal并不是一个Thread,而是Thread的局部变量。典型的应用莫过于Spring,Hibernate等框架中对于多线程的处理了

ThreadLocal设计的初衷:提供线程内部的局部变量,在本线程内随时随地可取,隔离其他线程。

备注:首先明确ThreadLocal不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的

疑问:如果每个线程都拥有自己的对象,那为什么不直接使用局部变量而是用ThreadLocal来修饰呢?

代码展示

构造方法

//只有这一个构造方法
public ThreadLocal() {

}


ThreadLocal中几个核心方法

/**
* 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 initialValue
* method to set the values of thread-locals.
*/
public void set(T value) {
Thread t = Thread.currentThread();//获得当前线程
ThreadLocalMap map = getMap(t);//获得当前线程对应的ThreadLocalMap对象
if (map != null)
map.set(this, value);
else
createMap(t, value);//创建一个新的ThreadLocalMap对象
}

/**
* 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 initialValue method.
*/
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();
}

/**
* 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  get
* method, unless the thread previously invoked the  set
* method, in which case the 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  remove followed by get.
*/
protected T initialValue() {
return null;
}

/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*/
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;
}

/**
* 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);
}


ThreadLocalMap代码

/**
* ThreadLocalMap is a customized hash map suitable only for
* maintaining thread local values. No operations are exported
* outside of the ThreadLocal class. The class is package private to
* allow declaration of fields in class Thread.  To help deal with
* very large and long-lived usages, the hash table entries use
* WeakReferences for keys. However, since reference queues are not
* used, stale entries are guaranteed to be removed only when
* the table starts running out of space.
*/
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> {//弱引用,以便及时被GC回收
/** The value associated with this ThreadLocal. */
Object value;

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

//省略以下代码

}


备注:从中我们可以发现这个Map的key是ThreadLocal变量,value为用户的值。

1.Thread类中有一个成员变量叫做ThreadLocalMap,它是一个Map,他的Key是ThreadLocal类
2.每个线程拥有自己的申明为ThreadLocal类型的变量,所以这个类的名字叫’ThreadLocal’:线程自己的(变量)
3.此变量生命周期是由该线程决定的,开始于第一次初始(get或者set方法)
4.由ThreadLocal的工作原理决定了:每个线程独自拥有一个变量,并非共享或者拷贝


总结:

ThreadLocal在jdbc Connection中使用(即多线程资源对象环境下使用)有应用场景。可以总结为一句话:ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。

ThreadLocal的设计思路:

每个Thread维护一个ThreadLocalMap映射表,这个映射表的key是ThreadLocal实例本身,

value是真正需要存储的Object。

管理非线程安全类的使用比试图使类成为线程安全的要更容易些。
非线程安全类通常可以安全地在多线程程序中使用,只要您能确保一个线程所用的类的实例不被其它线程使用。
例如,JDBC Connection 类是非线程安全的 — 两个线程不能在小粒度级上安全地共享一个
Connection — 但如果每个线程都有它自己的 Connection ,
那么多个线程就可以同时安全地进行数据库操作。


参考

1.http://www.tuicool.com/articles/emIVVvf

2.http://www.ibm.com/developerworks/cn/java/j-threads/index3.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java threadloca