ThreadLocal面试题总结

ThreadLocal概念

ThreadLocal 是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。

面试总结

先说Thread,也就是我们的线程类,在这个类里面有一个Map成员变量,源码如下

/* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
这个值初始为null。

再看ThreadLocal这个类,学习这种类,一般从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();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

我们可以看到,先获得当前线程对象,再获得线程对象里的Map,进行设值。
这里再看看这个Map是什么东东
ThreadLocalMap是ThreadLocal类里面的一个静态内部类,这是一个Map结构的类,当然这里并不是探讨数据结构,
你可以简单的把他当成HashMap或者TreeMap(注:千万不要这样对面试官说,我这么说是为了你们更好理解ThreadLocal)
如同所有Map数据结构,里面必然有一个内部类Entry(不懂数据结构的可以去看看TreeMap的内容,初期不用太深入,看看里面大概有几个成员变量就行)
Entry源码:

static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

我们会发现这个Entry的key在父类里设置super(k),而WeakReference是一个弱引用,即这个key是弱引用
(引用分强软弱虚,平时写的就是强引用,软引用就是当你内存不足的时候gc会删除,弱引用就是每执行gc就会删除,虚引用设计堆外内存暂时不扩展)

这里就有面试点,为什么这个key是弱引用,为什么不用强引用
我们知道gc回收有个可达性算法,当一个东东不被引用就会删除,假如key用强引用即使ThreadLocal不被我们引用了,也还有一个强引用的key拉着这个ThreadLocal让他不被回收,这就是ThreadLocal的第一个内存泄漏
用弱引用就是因为弱引用不像强引用那样,相当于我们不用ThreadLocal了,gc就会吧ThreadLocal给回收

这里面试还会问第二个面试点,即哪怕ThreadLocal被回收了但是Thred线程对象里的Map还在,这就是ThreadLocal的第二个内存泄漏点
那么如何解决呢,其实很简单,不用的k-v,直接调用ThreadLocal的remove()方法就可以了,这样就不会内存泄漏,这点切记要remove

当然还可能有一些2b的问题,为什么Thred线程对象内要用Map
答:一个Thred对象可能不只是对应一个ThreadLocal,可以是多个,这里再看set方法的源码

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

set的key是什么?是this,this是什么,是当前ThreadLocal对象。

顺着这条路看源码再看看csdn别人说的,对照着学习最终才是自己的内容,任何脱离源码的讲解都是扯蛋,哪怕扯得再圆

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值