ThreadLocal作用
ThreadLocal用来存储线程的局部变量,不同线程之间的数据私有化,不能共享。在多线程环境下就不会有线程安全问题。ThreadLocal可以用来存储数据库连接、Session等,达到了线程隔离的目的。
ThreadLocal的使用
在不同的线程上进行set(),get()取出的就是在该线程下的值。
ThreadLocal<String>local = new <String>ThreadLocal();
local.set("main");
Thread thread1 = new Thread(){
@Override
public void run() {
local.set("zhangsan");
System.out.println("Thread1"+local.get());
}
};
thread1.start();
System.out.println("Thread2"+local.get());
ThreadLocal源码分析
set源码
从源码看出,set方法先是通过当前线程获取ThreadLocalMap,不为空,则将当前ThreadLocal对象作为key,当前ThreadLocal存储的值作为value存储put进map中。如果map为空,则先创建map,再讲key-value存入。这里的map类似于HashMap的结构
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap的结点的结构
ThreadLocalMap是由Entry构成,结点里key为ThreadLocal对象,并且是一个弱引用,弱引用的对象在JVM垃圾回收的时候,一定会被回收,但是value是强引用。这样会导致即使结点已经不可用了也不会被回收,造成内存泄漏。
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
回收key为null的结点
当调用set(),remove(),get()方法时,内部都会调用expungeStaleEntry(),对key为null的结点进行清除。
if (k == null) {
e.value = null;
tab[i] = null;
size--;
}
线程池的ThreadLocal
当使用线程池管理线程时,线程时可以复用的,那么要及时remove(),否则会导致业务逻辑上的错误。
面试题
ThreadLocal原理
- ThreadLocal概念:ThreadLoal 变量存储线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本。
- 原理:Thread线程包含ThreadLocalMap指向threadLocals引用,Map存储Entry结点,每个结点由ThreadLocal弱引用和value强引用。通过当前线程获取线程的ThrreadLocalMap,然后再通过Map存取每个线程独有的副本,通过get()方法获取,set()方法赋值。
每个线程的ThreadLocalMap是什么时候创建的?
- 在第一次调用set()方法时调用
扩容算法
探测性清除
调用set(),get(),remove()方法时,遇到key为null的过期数据会进行清除,为了防止出现内存泄漏。
网友评论