ThreadLocal
作用
ThreadLocal
是本地线程变量,而ThreadLocal
中寄存的是该线程的变量,且只能被本线程拜访。ThreadLocal
为每个线程都创立了变量正本,从而防止了并发拜访抵触。
上面让咱们来看一个例子:
public class ThreadLocalTest02 { public static void main(String[] args) { ThreadLocal<String> local = new ThreadLocal<>(); IntStream.range(0, 10).forEach(i -> new Thread(() -> { local.set(Thread.currentThread().getName() + ":" + i); System.out.println("线程:" + Thread.currentThread().getName() + ",local:" + local.get()); }).start()); }}输入后果:线程:Thread-0,local:Thread-0:0线程:Thread-1,local:Thread-1:1线程:Thread-2,local:Thread-2:2线程:Thread-3,local:Thread-3:3线程:Thread-4,local:Thread-4:4线程:Thread-5,local:Thread-5:5线程:Thread-6,local:Thread-6:6线程:Thread-7,local:Thread-7:7线程:Thread-8,local:Thread-8:8线程:Thread-9,local:Thread-9:9
从后果能够看到,每一个线程都有本人的local 值,这就是TheadLocal的根本应用 。
上面咱们从源码的角度来剖析一下,ThreadLocal的工作原理。
ThreadLocal 源码剖析
1、set
办法
/** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread's copy of * this thread-local. */public void set(T value) { //首先获取以后线程对象 Thread t = Thread.currentThread(); //获取线程中变量 ThreadLocal.ThreadLocalMap ThreadLocalMap map = getMap(t); //如果不为空, if (map != null) map.set(this, value); else //如果为空,初始化该线程对象的map变量,其中key 为以后的threadlocal 变量 createMap(t, value);}/** * Create the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * @param t the current thread * @param firstValue value for the initial entry of the map *///初始化线程外部变量 threadLocals ,key 为以后 threadlocalvoid createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue);}/** * Construct a new map initially containing (firstKey, firstValue). * ThreadLocalMaps are constructed lazily, so we only create * one when we have at least one entry to put in it. */ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY);}static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; }}
其中ThreadLocalMap
是ThreadLocal
的一个动态外部类,外面定义了Entry
来保留数据。而且是继承的弱援用。在Entry
外部应用ThreadLocal
作为key
,应用咱们设置的value
作为value
。对于每个线程外部有个ThreadLocal.ThreadLocalMap
变量,存取值的时候,也是从这个容器中来获取。
2、get
办法
/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local */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();}
通过下面的剖析,置信你对该办法曾经有所了解了,首先获取以后线程,而后通过key threadlocal
获取设置的value
。
ThreadLocal 内存泄露问题是怎么导致的?
ThreadLocalMap
中应用的 key 为 ThreadLocal
的弱援用,而 value 是强援用。所以,如果 ThreadLocal
没有被内部强援用的状况下,在垃圾回收的时候,key 会被清理掉,而 value 不会被清理掉。
这样一来,ThreadLocalMap
中就会呈现 key 为 null 的 Entry。如果咱们不做任何措施的话,value 永远无奈被 GC 回收,这个时候就可能会产生内存泄露。ThreadLocalMap
实现中曾经思考了这种状况,在调用 set()
、get()
、remove()
办法的时候,会清理掉 key 为 null 的记录。应用完 ThreadLocal
办法后最好手动调用remove()
办法
static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; }}
弱援用介绍:
如果一个对象只具备弱援用,那就相似于可有可无的生活用品。弱援用与软援用的区别在于:只具备弱援用的对象领有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具备弱援用的对象,不论以后内存空间足够与否,都会回收它的内存。不过,因为垃圾回收器是一个优先级很低的线程, 因而不肯定会很快发现那些只具备弱援用的对象。
弱援用能够和一个援用队列(ReferenceQueue)联结应用,如果弱援用所援用的对象被垃圾回收,Java 虚拟机就会把这个弱援用退出到与之关联的援用队列中。
著作权归Guide所有 原文链接:https://javaguide.cn/java/concurrent/java-concurrent-question...
参考文献:ThreadLocal,一篇文章就够了 - 知乎 (zhihu.com)