资讯专栏INFORMATION COLUMN

ThreadLocal源码

岳光 / 1952人阅读

摘要:下来我们来看中的方法。从中可以看到真正保存的是在中,接着看看的源码。数组的初始长度为,最多可保存一旦超过就进行扩容增加一倍。而内部利用数组来保存和值的,数组的索引就是的哈希值数组的长度。

在Android-27中查看源码:

在Looper源码中,我们看到通过ThreadLocal的set方法来保存Looper,通过get方法来取出Looper。下来我们来看ThreadLocal中的set/get方法。

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    } 
    
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
    
    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();
    }
    
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

从中可以看到真正保存的是在Thread.threadLocals中,接着看看ThreadLocalMap的源码。

在ThreadLcoalMap中
    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);
        } 
        
    private void set(ThreadLocal key, Object value) {

            // We don"t use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

在ThreadLcoalMap中创建了数组,利用数组来保存Entry,Entry中保存了ThreadLocal和值。数组的初始长度为16,最多可保存length/2一旦超过就进行扩容(增加一倍)。

所以ThreaLocal的作用是用来实现线程内部的数据共享,其实现原理是利用线程内部的ThreaLocalMap来保存数据。而ThreadLocalMap内部利用数组来保存ThreadLocal和值的,数组的索引就是ThreadLocal的哈希值&(数组的长度-1)。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72114.html

相关文章

  • 追踪解析 ThreadLocal 源码

    摘要:虽然类名中带有字样,但是实际上并不是接口的子类。是弱连接接口,这意味着如果仅有指向某一类,其任然有可能被回收掉。这里使用弱连接的意义,是为了防止业务代码中置空对象,但是由于存在连接可达,所以仍然无法回收掉该对象的情况发生。 零 前期准备 0 FBI WARNING 文章异常啰嗦且绕弯。 1 版本 JDK 版本 : OpenJDK 11.0.1 IDE : idea 2018.3 2 T...

    wawor4827 评论0 收藏0
  • 深入理解Python中的ThreadLocal变量(中)

    摘要:在深入理解中的变量上中我们看到的引入,使得可以很方便地在多线程环境中使用局部变量。特别需要注意的是,基类的并不会屏蔽派生类中的创建。到此,整个源码核心部分已经理解的差不多了,只剩下用来执行清除工作。 在 深入理解Python中的ThreadLocal变量(上) 中我们看到 ThreadLocal 的引入,使得可以很方便地在多线程环境中使用局部变量。如此美妙的功能到底是怎样实现的?如果你...

    DataPipeline 评论0 收藏0
  • 您有一份ThreadLocal完全解析手册

    摘要:返回索引位置的值。因为依赖于静态成员变量的关系,所以它的肯定唯一获取当前线程。位置还没有初始化第一次这个,直接将放到的位置。在线程池模式下,生命周期伴随着线程一直存在,可能出现内存泄漏的情况,最好手动调用方法。 本文原创地址,:jsbintask的博客(食用效果最佳),转载请注明出处! 前言 ThreadLocal是jdk中一个非常重要的工具,它可以控制堆内存中的对象只能被指定线程访问,如...

    刘东 评论0 收藏0

发表评论

0条评论

岳光

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<