TheadLocal
ThreadLocal是什么
ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
ThreadLocal为什么保证线程私有
ThreadLoal 变量,线程局部变量
,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本。这里有几点需要注意:
1. 因为每个 Thread 内有自己的实例副本,且该副本只能由当前 Thread 使用。这是也是 ThreadLocal 命名的由来。
2. 既然每个 Thread 有自己的实例副本,且其它 Thread 不可访问,那就不存在多线程间共享的问题。
3. ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例本。
4. ThreadLocal 变量通常被private static修饰。当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收。
ThreadLocal实现原理
每个线程内都有一个内部的成员变量 ThreadLocalMap
,起到线程隔离的是每个线程内的ThreadLocalMap集合,ThreadLocal起到的作用的关联资源对象。
ThreadLocalMap这个变量用于存储资源对象:
- 调用set方法,就是以当前ThreadLocal作为Key,资源对象为Value,存入ThreadLocalMap中
- 调用get方法,就是以当前ThreadLocal作为Key,从资源对象中获取相对应的资源
- 调用remove方法,就是以当前ThreadLocal作为Key,从资源对象中移除相对应的资源
下图可以直观看出三者Thread、ThreadLocal、ThreadLocalMap的关系
ThreadLocal的简单使用
public class ThreadLocaDemo {
private static ThreadLocal<String> localVar = new ThreadLocal<String>();
static void print(String str) {
//打印当前线程中本地内存中本地变量的值
System.out.println(str + " :" + localVar.get());
//清除本地内存中的本地变量
localVar.remove();
}
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
public void run() {
ThreadLocaDemo.localVar.set("local_A");
print("A");
//打印本地变量
System.out.println("after remove : " + localVar.get());
}
},"A").start();
Thread.sleep(1000);
new Thread(new Runnable() {
public void run() {
ThreadLocaDemo.localVar.set("local_B");
print("B");
System.out.println("after remove : " + localVar.get());
}
},"B").start();
}
}
A :local_A
after remove : null
B :local_B
after remove : null
ThreadLocalMap 为什么会引起内存泄漏?
只要问到ThreadLocal,大概率会问到这个问题。这一部分多看一下,不需要死记硬背,要能够按照自己的理解说出来。
由 于 ThreadLocalMap 的 生 命周 期 跟 Thread 一 样 长, 如 果没有手动remove去删除对 应 key 就 会 导致 内 存 泄漏 。
ThreadLocal的remove方法
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
ThreadLocalMap 使用 ThreadLocal 的弱引用作为 key,如果一个 ThreadLocal 没有外部强引用来引用它,那么系统 垃圾回收 的时候,这个 ThreadLocal 势必会被回收,这样一来,ThreadLocalMap 中就会出现 key 为 null 的 Entry,就没 有办法访问这些 key 为 null 的 Entry 的 value,如果当前线程再迟迟不结束的话,这些 key 为 null 的 Entry 的 value 就会一直存在,造成内存 泄漏。