ThreadLocal并不是一个Thread,而是Thread的局部变量。
*ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。
ThreadLocalMap:是ThreadLocal的一个内部类
// ThreadLocalMap is a customized hash map suitable only for maintaining thread local values
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
// 这个Map的key是ThreadLocal变量,value为用户的值
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
/**
* Get the map associated with a ThreadLocal. Overridden in InheritableThreadLocal.
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
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;
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
// 每个线程拥有自己的threadLocalMap
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
}
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
ThreadLocalMap map = getMap(t);
if (map != null) {
// 在此线程的ThreadLocalMap中查找key为当前ThreadLocal对象的entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
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;
}
总结,ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。
1、每个线程中都有一个独有的ThreadLocalMap。
2、ThreadLocal类通过操作每一个线程特有的ThreadLocalMap,从而实现了变量访问在不同线程中的隔离。ThreadLocalMap存储的键值对中的键是this对象指向的ThreadLocal对象,而值就是你所设置的对象了。
ThreadLocal适用场景:
变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。
- DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是一个线程安全的变量。而我们每个线程都需要使用他,并且各自使用各自的。
- 一些不能通过参数传递的东西。由于Spring在AOP后并不能向应用程序传递參数。应用程序的每一个业务代码是事先定义好的,Spring并不会要求在业务代码的入口參数中必须编写Connection的入口參数。此时Spring选择了ThreadLocal,通过它保证连接对象始终在线程内部,不论什么时候都能拿到。
- log4j中的mdc。比如log4j中的mdc链路追踪。MDC(Mapped Diagnostic Context,映射调试上下文)是Slf4j(提供了接口定义和核心实现,日志库负责适配器的实现)提供的一种方便在多线程条件下记录日志的功能。MDC 可以看成是一个与当前线程绑定的Map,可以往其中添加键值对。MDC 中包含的内容可以被同一线程中执行的代码所访问。当前线程的子线程会继承其父线程中的 MDC 的内容。当需要记录日志时,只需要从 MDC 中获取所需的信息即可。MDC 的内容则由程序在适当的时候保存进去。对于一个 Web 应用来说,通常是在请求被处理的最开始保存这些数据。简而言之,MDC就是日志框架提供的一个InheritableThreadLocal,项目代码中可以将键值对放入其中,然后使用指定方式取出打印即可。