ThreadLocal
早在JDK 1.2 的版本中就提供 java.lang.ThreadLocal .
ThreadLocal为解决多个线程并发问题提供了一种新的思路。
是一个工具类,可以很简洁的编写出多线程
ThreadLocal 很容易我们理解为本地线程,ThreadLocal并不是一个线程,而是线程中的一个局部变量。
ThreadLocal 为每个线程提供独立的变量副本,每个线程都可以改变自己的副本,不会影响其它线程多多对应的副本
ThreadLocal使用场景
多个线程共享同一个数据,会引发线程安全问题,虽然可以使用synchronized 和 Lock
避免安全问题,但难免多个线程存在资源争夺问题。
那么如何解决线程下效率低问题呢?
让每个线程都是用自己独立的数据,不和别的线程共享,就可以多个线程避免资源争夺问题
实例:
public class Test2 {
public static void main(String[] args) {
ThreadLocal<Integer> t = new ThreadLocal<>();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
t.set(10);//10
System.out.println(t.get());
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
/*每个线程独立的数据 不共享*/
System.out.println(t.get());//null
t.set(10);
System.out.println(t.get());//10
}
});
t2.start();
}
}
ThreadLocal 存储分析
ThreadLocal只是操作本地线程隔离的数据的工具类,它本身并不是存储数据的,真正存储数据的是线程Thread对象本身。
通过源码我们可看到Thread类中有存在的ThradLocade
Thread部分源码:
/* 属于这个线程的ThreadLocal值。这个Map保留了下来
通过ThreadLocal类。 */
ThreadLocal.ThreadLocalMap threadLocals = null;

查看ThreadLocal类 get 和 set 方法发现:
使用set 方法时,是获取当前线程,然后获取当前线程的 threadLocals,然后将value赋值给当前线程的threadLocals
/**
*设置此线程本地变量的当前线程的副本
*到指定的值。大多数子类将不需要这样做
*重写此方法,仅依赖于{@link #initialValue}
*方法设置线程局部变量的值。
*要存储在当前线程的副本中的值
*这个线程局部。
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
getMap源码
/ * *
* 获取与ThreadLocal关联的映射。覆盖在
* InheritableThreadLocal。
*
* @param t当前线程
* @返回Map
* /
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
使用ThradLocal类get方法时,获取当前线程,然后获取当前线程副本的value
/ * *
*返回当前线程的这个副本的值
*线程局部变量。如果变量没有值
*当前线程,它首先被初始化为返回的值
*通过调用{@link #initialValue}方法。
*
* @返回当前线程的线程本地值
* /
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
ThreadLocal 内部类 ThreadLocalMap源码
/ * *
* ThreadLocalMap是一个定制的哈希映射,只适用于
*维护线程本地值。不导出操作
*在ThreadLocal类的外部。类是包私有的
*允许在类线程中声明字段。帮助处理
*非常大且长期存在的用法,哈希表条目使用
*键的弱引用。但是,因为引用队列不是
*已使用的陈旧条目保证仅在以下情况下被删除
*这个表开始没有空间了。
* /
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/**与这个ThreadLocal关联的值*/
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}