ThreadLocal
https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20%E5%B9%B6%E5%8F%91.md#2-%E7%BA%BF%E7%A8%8B%E6%9C%AC%E5%9C%B0%E5%AD%98%E5%82%A8thread-local-storage
ThreadLocal,即线程变量
常用的3个方法:set()、get()、remove()。都是线程安全的。
一个ThreadLocal在一个线程中是共享的,在不同线程之间又是隔离的(每个线程都只能看到自己线程的值)
public class ThreadLocalExample1 {
public static void main(String[] args) {
ThreadLocal threadLocal1 = new ThreadLocal();
ThreadLocal threadLocal2 = new ThreadLocal();
Thread thread1 = new Thread(() -> {
threadLocal1.set(1);
//threadLocal1.set(11);会覆盖上面的set(1)
threadLocal2.set(1);
});
Thread thread2 = new Thread(() -> {
threadLocal1.set(2);
threadLocal2.set(2);
});
thread1.start();
thread2.start();
}
}
ThreadLocal原理
每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
set
ThreadLocal.ThreadLocalMap threadLocals = null;
...
public void set(T value) {
Thread t = Thread.currentThread();
//获取当前线程的ThreadLocalMap;
ThreadLocalMap map = getMap(t);
if (map != null)
//this是调用set()方法的localthread对象;
map.set(this, value);
else
createMap(t, value);
}
...
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
set()先获取当前线程的ThreadLocalMap,然后将调用set()方法的localthread对象作为key存储value,
这样的话,ThreadLocal threadLocal1 = new ThreadLocal(),线程a调用threadLocal1.set方法时,线程a会创建ThreadLocalMap对象,key是threadLocal1;
当线程调用threadLocal1.get时,线程a便会到自己的ThreadLocalMap中,根据key==threadLocal1获取value,这样便是线程安全的,每个线程都有自己的ThreadLocalMap
get
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();
}
get方法,先获取当前线程的ThreadLocalMap,然后根据将调用get()方法的localthread对象作为key获取value;
ThreadLocal内存泄漏
内存泄露:程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重;
ThreadLocalMap的key
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
...
}
如上图,每一个Thread维护一个ThreadLocalMap,key弱引用,外部的ThreadLocalRef是key的强引用,一旦ThreadLocalRefnull,GC时key就会被回收,但是value还存在强引用,只有CurrentThreadRefnull,value才会被回收;
这些key为null的Entry的value就会一直存在一条强引用链
CurrentThreadRef -> CurrentThread -> ThreaLocalMap -> Entry -> value
public class ThreadLocalExample1 {
public static void main(String[] args) {
ThreadLocal threadLocal1 = new ThreadLocal();
Thread thread1 = new Thread(() -> {
while(true){
threadLocal1.set(1);
}
});
threadLocal1 = null;
System.GC();//如果在这里发生GC,那么threadLocal1以及thread1的ThreaLocalMap的key会被回收,但是value不会被回收;
thread1.start();
}
}
https://blog.csdn.net/puppylpg/article/details/80433271
https://zhuanlan.zhihu.com/p/102571059