ThreadLocal是JDK自带的一个类,他的作用是为每个线程中创建专属本地变量,这些变量只能被当前线程访问和修改,其他线程无法访问,当你创建了一个ThreadLocal里的变量后,每个访问这个变量的线程都会获得一个此变量的本地副本,同时THreadLocal提供了get()、set()方法来获取默认值,或将其值更改为当前线程所存的副本的值。 在ThreadLocal的源码中可以发现,其set()方法实际上是通过Thread.currentThread()方法获取当前的线程,再通过getMap获得当前线程的ThreadLocalMap对象,对该对象进行if/else判断,判断这个map是否为空,如果不为空,就往ThreadLocalMap中加入一个键值对,键是ThreadLocal对象,值则是set方法中传入的想要在该线程中存储来进行共享的变量副本,如果为空,那就创建一个新的ThreadLocal对象,并将其存储到该Map中。 get()方法与set()方法前面一样,都是获得当前线程的ThreadLocalMap对象,再对map是否为空其进行判断,如果不为空:1、获取其当前ThreadLocal的键值对对象;2、对获取到的键值对对象进行非空判断,不为空则将键值对的值返回出去,为空则不做处理;如果为空,那么不进入if中,调用setInitialValue()方法来获取初始值,并将其设置为当前线程的变量副本。
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(); } public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { map.set(this, value); } else { createMap(t, value); } }
ThreadLocal很有用,但是也存在一些问题,1、内存泄露问题,由于ThreadLocalMap中使用的key是弱引用,而value是强引用,所以如果ThreadLocal没有被外部强引用的时候,如果发生垃圾回收,key会被清理掉,而value不会被清理掉,一旦发生,ThreadlocalMap中就会出现一个key为null的键值对,如果不做处理,value就永远无法被回收,就会产生内存泄漏;2、如果线程数量非常庞大,ThreadlocalMap的查询效率可能会降低,可以考虑使用线程池来控制线程的创建和销毁,来减少ThreadlocalMap的大小,但是如果使用线程池复用线程时没有清除ThreadLocal变量,可能会导致线程之间共享ThreadLocal变量;为了解决以上问题,ThreadlocalMap也提供了一个remove()方法,会清理掉key为null的记录,建议在通过try/catch/finally中的finally代码块来调用remove(),确保其一定会执行。
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) { m.remove(this); } }
标签:map,存在,Thread,ThreadLocalMap,value,ThreadLocal,线程,作用 From: https://www.cnblogs.com/hwj7/p/17641503.html