ThreadLocal
ThreadLocal简介:
ThreadLocal叫做线程局部变量,其中填充的变量属于当前线程,对于其他的线程是隔离的,属于线程私有。ThreadLocal会为每个线程中都创建一个工作副本,而每个线程都只可以访问自己内部的副本变量。
ThreadLocal特点:
- ThreadLocal提供了线程本地的实例副本,该副本只能由当前的Thread使用
- 因为每个Thread都有自己的实例副本,且其他Thread不可以访问,也就不会存在共享的问题
- 当一个线程结束时,他说使用的所有 ThreadLocal 相对的实例副本都可被回收
- ThreadLocalMap其实是Thread线程的一个属性值,而ThreadLocal是维护ThreadLocalMap
ThreadLocal与Synchronize的区别
- synchronize侧重于线程间的数据共享,而ThreadLocal则更偏向与线程间的数据隔离
- synchronize是利用锁的机制,使变量或者方法在某一时刻只能被一个线程访问,而ThreadLocal为每个线程都提供了一个副本,使得每个线程在同一时间访问到的并不是同一个对象,隔离了多个线程间的数据共享
ThreadLocal方法分析
set方法
public void set(T value) { //1、首先获取当前线程 Thread t = Thread.currentThread(); //2、获取线程中的ThreadLocalMap属性,如果ThreadLocalMap不为空,则直接 //保存要保存的变量值,否则就创建ThreadLocalMap,并赋值 ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } //创建ThreadLocalMap void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
其中ThreadLocalMap是ThreadLocal中的静态内部类,而它的内部中的构成Entry继承了WeakReference弱引用,用来保存数据。在Entry内部使用ThreadLocal作为key,使用我们设置的value作为value。
get方法
public T get() { //获取当前线程 Thread t = Thread.currentThread(); //获取当前线程的ThreadLocalMap ThreadLocalMap map = getMap(t); if (map != null) { //从当前线程的ThreadLocalMap中获取Entry对象 ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } //如果没有就返回null return setInitialValue(); } private T setInitialValue() { //将value值设置为null T value = initialValue(); //获取当前线程的对象 Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) //如果map不为null,就给当前map设置值 map.set(this, value); else //否则就创建map createMap(t, value); return value; } ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
remove方法
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
remove方法直接将线程ThreadLocal中的ThreadLocalMap删除,如果不删除,很有可能会发生内存泄露。
ThreadLocal为什么容易发生内存泄露
ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用,弱引用的特点是,如果这个对象只存在弱引用,那么在下一次垃圾回收的时候必然会被清理掉。如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候会被清理掉的,这样一来 ThreadLocalMap中使用这个 ThreadLocal 的 key 也会被清理掉。但是,value 是强引用,不会被清理,这样一来就会出现 key 为 null 的 value。