一次threadlocal的源码分析思路

  • 一:什么是threadlocal?

首先看下jdk里面的解释(来自于百度翻译)

简单的总结就是:

ThreadLocal提供了线程的本地变量,他可以保证访问到的变量属于当前线程,每个线程都保存有一个变量的副本,每一个线程的变量都不同,ThreadLocal提供了一种线程的隔离,将变量与线程绑定.

ThreadLocal通过threadLocalHashCode来标识每一个threadLocal的唯一性,threadLocalHashCode通过CAS操作进行更新,每次hash操作的增量为0× 0x61c88647

可以看下他的set方法

通过Thread.currentThread()方法获取了当前的线程引用,并传给了getMap(Thread)方法获取一个ThreadLocalMap的实例。

继续看往下看源码:

可以看到getMap(Thread)方法直接返回Thread实例的成员变量threadLocals。它的定义在Thread内部,访问级别为package级别

但后打开我们的thread类;

到了这里我们可以看出,每一个Thread类里面都有一个ThreadLocal.ThreadLocalMap的成员变量,也就是说每个线程通过ThreadLocal.ThreadLocalMap与ThreadLocal相绑定,这样可以确保每个线程访问到thread-local variable都是本线程.

继续往下走,获取了ThreadLocalMap实例以后,如果他不能为空则调用ThreadLocal的createMap方法,new一个ThreadLocalMap实例并且赋值给Thread.threadLocals

ThreadLocal 的 createMap方法的源码如下:

再往下;ThreadLocal 的 get 方法

通过Thread.currentThread()方法获取了当前的线程引用,并传给了getMap(Thread)方法获取一个ThreadLocalMap的实例。继续跟进setInitialValue()方法:

首先调用 initialValue()方法来初始化,然后 通过Thread.currentThread()方法获取了当前的线程引用,并传给了getMap(Thread)方法获取一个ThreadLocalMap的实例,并将 初始化值存到ThreadLocalMap 中。

接下来我们来看看ThreadLocalMap的实现

ThreadLocalMap是ThreadLocal的静态内部类

 /**
     * ThreadLocalMap is a customized hash map suitable only for
     * maintaining thread local values. No operations are exported
     * outside of the ThreadLocal class. The class is package private to
     * allow declaration of fields in class Thread.  To help deal with
     * very large and long-lived usages, the hash table entries use
     * WeakReferences for keys. However, since reference queues are not
     * used, stale entries are guaranteed to be removed only when
     * the table starts running out of space.
     */
    static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

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

        /**
         * The initial capacity -- MUST be a power of two.
         */
        private static final int INITIAL_CAPACITY = 16;

        /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         */
        private Entry[] table;

        /**
         * The number of entries in the table.
         */
        private int size = 0;

        /**
         * The next size value at which to resize.
         */
        private int threshold; // Default to 0

        /**
         * Set the resize threshold to maintain at worst a 2/3 load factor.
         */
        private void setThreshold(int len) {
            threshold = len * 2 / 3;
        }

        /**
         * Increment i modulo len.
         */
        private static int nextIndex(int i, int len) {
            return ((i + 1 < len) ? i + 1 : 0);
        }

        /**
         * Decrement i modulo len.
         */
        private static int prevIndex(int i, int len) {
            return ((i - 1 >= 0) ? i - 1 : len - 1);
        }

        /**
         * 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);
        }

(截图无法满足要求,直接把代码copy出来)

其中INITIAL_CAPACITY代表这个Map的初始容量;1是一个Entry类型的数组,用于存储数据;size代表表中的存储数目;threshold代表需要扩容时对应size的阈值。Entry类是ThreadLocalMap的静态内部类,用于存储数据。Entry类继承了WeakReference<ThreadLocal<?>>,即每个Entry对象都有一个ThreadLocal的弱引用(作为key),这是为了防止内存泄露。一旦线程结束,key变为一个不可达的对象,这个Entry就可以被GC了。接下来我们来看ThreadLocalMap 的set方法的实现:

ThreadLocal 的get方法会调用 ThreadLocalMap 的 getEntry(ThreadLocal key) ,其源码如下:

总结了下;

每个线下的内部都有一个名字为threadLocals的成员变量,该变量的类型为HashMap,其中的key是我们定义的ThreadLocal变量的this引用,values则为我们set时候的值,每个线程本地变量是存到线程自己的内部线程自己的内存变量threadLocals里面的,如果当前线程一直不消失那么这些本地变量会一直存到,所以可能会造成内存溢出,,所以使用完毕后要记得调用ThreadLocal的remove方法删除对应线程的threadLocals中的本地变量。

如果你有更加好的方法或者思路可以一起学习一起进步,欢迎一起学习

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值