ThreadLocal的简单使用

ThreadLocal的简单使用

  • ThreadLocal在线程内部调用set(value)方法存储值。
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方法内部,我们获取到当前线程对象,通过ThreadLocal成员方法getMap(t)根据当前线程对象获取到当前线程的的成员属性变量threadLocals(变量类型是ThreadLocalMap,在createMap(t,value)中初始化)这是key-value存储容器,我们调用这个threadLocals来实现保存和修改数据的操作。保存数据有两种方式,一个通过ThreadLocalMap的成员方法set(this, value),通过ThreadLocal成员方法 createMap(t, value)实现。

  • ThreadLocal的成员方法createMap(线程对象,value)
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

createMap内部我们直接调用ThreadLocalMap的构造函数传入当前ThreadLocal对象和要保存的数据值创建该对象,并把该对象的引用传递给当前线程的属性变量threadLocals

  • ThreadLocalMap的构造函数
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);
        }

ThreadLocalMap(threadLocal,firstValue)构造函数内部,我们初始化了一个Entry对象(EntryThreadLocalMap的静态内部类,继承了WeakReference对象),这个对象存储了传入的ThreadLocal对象和数据对象。我们把这个对象加入一个初始化长度为16的Entry类型的数组表中。

  • ThreadLocalMap的成员方法set(this, value)
private void set(ThreadLocal<?> key, Object value) {
            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();
        }

set(threadLocal, value)的方法内部,我们会先遍历table表判断是否存在存储了该ThreadLocal对象的entry存在,如果存在则替换数据值,不存在则新建entry对象,加入到table表中。

  • ThreadLocal在线程内部调用get()方法获取值。
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();
    }

在get方法内部,我们首先获取到当前线程对象,再通过当前线程对象获取到它的属性变量threadLocals,调用它的getEntry(threadLocal)获取到Entry对象,通过Entry对象我们可以直接获取到值。

  • 总结
    ThreadLocal为每一个线程都单独维护了一个ThreadLocalMap对象,其中一个线程通过ThreadLocal存储或者修改他的数据对象时,不会影响到其他线程。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章