Understanding ThreadLocal And InheritableThreadLocal

ThreadLocal原理与应用
本文深入探讨了ThreadLocal的工作原理,包括其set和get方法的实现细节,解释了如何通过ThreadLocalMap为不同线程存储独立的数据副本。此外,还讨论了弱引用和继承线程局部变量的概念。

Use ThreadLocal Example

// create static global reference s1(type: ThreadLocal)
public static ThreadLocal<String> s1 = new ThreadLocal<String>();

// then set value in thread (just which thread run it)
s1.set("value");

//  then you can get the value where the thread is running 
s1.get();

//在线程池环境中需要手动移除它,(线程终止会自动移除ThreadLocal,但线程池的线程还会继续使用)
s1.remove()

The Magic of ThreadLocal

只有一个静态引用(s1),但是却可以在不同的线程中取到不同的值,why?

先看一下 set 方法

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);  //从这里可以看出 每个线程对应一个 ThreadLocalMap 
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

// 先来看初次赋值
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue); // 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);
        }
  1. 每个线程对应一个 ThreadLocalMap
  2. ThreadLocalMap的key 的值就是 ThreadLocal 本身(s1),value 就是 set 传入的值

我们再来看一下 get 方法

public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);  //取出(s1)对应的值
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

get 方法就是简单的取值

Deep In TheadLocal (weakReference and weakHashMap)

我们从上面知道 ThreadLocalMap 是线程存储ThreadLocal的地方,它类似于WeakHashMap:

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

上面我们看到,entry 的key 存储的是ThreadLocal (s1)的应用,但是这个引用是个弱引用:

key -------(弱引用)----->> ThreadLocal Instance <<------强引用 -------s1

所以如果 s1=null,那么 ThreadLocal Instance 是会被回收的

so why we should use WeakReference?

InheritableThreadLocal

作用就是在子进程中可以取到父进程的ThreadLocal的值。

/*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.
     */
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

InheritableThreadLocal 也只是存储在 ThreadLocalMap 里的

InheritableThreadLocal which subclasses ThreadLocal class is used in such situations. This class has only one method 'protected Object childValue(Object parentValue)' which is used to set the initial value of the InheritableThreadLocal variable in the child thread as a function of a ThreadLocal variable (passed as a parameter) in the parent thread. This method is called from within the parent thread before the child thread is created and the default implementation will make the child values identical to parent's, but we can override the childValue() method to set the child value as a function of the parent value for those ThreadLocals which have values in the parent thread. By default the childValue() returns the same input argument, but again an override of the childValue method might change this behavior as well.

唯一的疑问就是什么时候给子线程的inheritableThreadLocals 变量赋的值,就是在父进程创建子进程的时候 调用的 childValue(Object parentValue) 方法。

More

思考:涉及到线程池 和异步操作的时候要怎么传递ThreadLocal?

参考:Transmittable ThreadLocal(TTL)

转载于:https://my.oschina.net/tigerlene/blog/732397

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值