ThreadLocal模式主要是为了解决多线程并发访问的安全问题.
其中ThreadLocalMap对象是此模式的核心副本变量,如下Thread类中的变量:
public class Thread implements Runnable {
此处省略部分代码...
/** ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class.
*/
ThreadLocal.ThreadLocalMap threadLocals = null;
此处省略部分代码...
}
我们查看Thread线程类,发现有一个ThreadLocal.ThreadLocalMap变量.继续查看ThreadLocal源码:
<pre name="code" class="html">public class ThreadLocal<T>
{
//此处省略部分代码
protected T initialValue()
{
return null;
}
//得到当前线程中此ThreadLocal对应的value值
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();
}
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;
}
//将value值设置到当前线程中的ThreadLocal.ThreadLocalMap中存储.
public void set(T value)
{
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
//当map不为空时,则将该value和此ThreadLocal操作类保存在map对象中.
//确保当前线程中不同的ThreadLocal都有对应的副本
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public void remove()
{
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
//得到当前线程中的ThreadLocalMap对象
ThreadLocalMap getMap(Thread t)
{
return t.threadLocals;
}
//使用当前ThreadLocal和firstValue值创建一个新的Map并存入到Thread中
void createMap(Thread t, T firstValue)
{
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
/** 内部类 */
static class ThreadLocalMap
{
//此处省略部分代码
}
}
我们通过源代码可以看到每个线程都可以独立修改属于自己的副本而不会互相影响,从而隔离了线程和线程.避免了线程访问实例变量发生安全问题.
ThreadLocal只是操作Thread中的ThreadLocalMap对象的集合.
ThreadLocalMap变量属于线程的内部属性,不同的线程拥有完全不同的ThreadLocalMap变量.
线程中的ThreadLocalMap变量的值是在ThreadLocal对象进行set或者get操作时创建的.
使用当前线程的ThreadLocalMap的关键在于使用当前的ThreadLocal的实例作为key来存储value值.
ThreadLocal模式至少从两个方面完成了数据访问隔离,即纵向隔离(线程与线程之间的ThreadLocalMap不同)和横向隔离(不同的ThreadLocal实例之间的互相隔离).
当我们解读struts2核心分发器Dispatcher时,可以看到也是使用ThreadLocal模式来存储每个线程中副本变量来达到线程安全.如果使用synchronized同步锁将会大大影响web项目的访问效率.