美文网首页
线程-ThreadLocal

线程-ThreadLocal

作者: go_2021 | 来源:发表于2021-12-25 16:06 被阅读0次
    类结构:

    ThreadLocal类中有个ThreadLocalMap内部静态类。内部静态类和外部类,可以单独存在,创建各自不会触发对方的初始化。Entry又是ThreadLocalMap的内部静态类,是虚引用的子类,意味着EntryThreadLocal的引用是弱引用,ThreadLocal对象的GC和Entry对象没有关系。

    class ThreadLocal{
        static class ThreadLocalMap {
            static class Entry extends WeakReference<ThreadLocal<?>> {
                Object value;
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
        }}
    

    通过ThreadLocal类中的getset方法的分析,方法中操作的map是从Thread类中获取的,ThreadLocal只是map中Entry对象中的key

    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<String> aa = new ThreadLocal<>();
    aa.set("dfd");
    String s = aa.get();
    aa.remove();
    
    

    举个简单使用ThreadLocal的例子,在执行set的时候,会在当前线程中创建一个ThreadLocalMap实例,EntryThreadLocal实例 -> "dfd")
    这时候ThreadLocal的实例会被两个地方引用:

    • aa这个变量(强引用)
    • Entry(弱引用)

    代码执行完了,第一个引用就可以GC了,但是第二个Entry中的引用不会消失,如果是强引用,ThreadLocal就不会被GC,会产生内存泄漏。
    当Entry中的key- >ThreadLocal 被GC了,那么Entry中的value就没有意义存在了。这时候Thread->ThreadLocalMap->Entry->value的强引用关系还在,虽然已经获取不到value了,但是也不会被GC,所以需要手动remove去释放value这块儿内存。

    一般多线程如何使用?

    一般在多线程都会使用ThreadLocal的时候,ThreadLocal可以设置为静态变量,jvm唯一实例,因为每个线程会有自己的map,ThreadLocal只是个key,不会影响正常使用,还减少了ThreadLocal实例的创建。

    为啥ThreadLocalMap是内部静态类?

    因为内部静态类在创建,用的时候不用依赖外部类的实例。因为这个特性,可以用内部静态类来实现外部类的单例。
    子类InheritableThreadLocal可以直接创建ThreadLocalMap类的实例而不用通过ThreadLocal的实例获取。

    public class InheritableThreadLocal<T> extends ThreadLocal<T> {
        protected T childValue(T parentValue) {
            return parentValue;
        }
        ThreadLocalMap getMap(Thread t) {
           return t.inheritableThreadLocals;
        }
        void createMap(Thread t, T firstValue) {
            t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
        }
    }
    

    感觉从代码的角度来说ThreadLocalMap可以单独出来单独写一个类,这样梳理的时候比较简单。从逻辑的角度来说ThreadLocal是对外的线程本地概念的抽象,ThreadLocalMap是实现的内部逻辑,所以内部类比较合适。

    相关文章

      网友评论

          本文标题:线程-ThreadLocal

          本文链接:https://www.haomeiwen.com/subject/vrwlqrtx.html