Java 基础—— ThreadLocal

ThreadLocal 如何实现为每个线程提供一个独立的变量副本

一、核心
当使用ThreadLocal维护变量的时候 为每一个使用该变量的线程提供一个独立的变量副本

二、具体实现(源码)

当我们获取需要的元素时,通过的它的 get() 方法,那么就以这里为起点开始分析吧,源码如下

 /**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();	//获取当前线程对象
	    //获取 ThreadLocalMap 内部类对象,源码声明为: static class ThreadLocalMap 
        //本质上就是一个map
        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();									...............⑥
    }

从 ①开始吧:
通过 ①判断,map 不等于 null 时,就执行②,获取实体,它的源码如下:


        /**
         * Get the entry associated with key.  This method
         * itself handles only the fast path: a direct hit of existing
         * key. It otherwise relays to getEntryAfterMiss.  This is
         * designed to maximize performance for direct hits, in part
         * by making this method readily inlinable.
         *
         * @param  key the thread local object
         * @return the entry associated with key, or null if no such
         */
        private Entry getEntry(ThreadLocal<?> key) {
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }

然后③判断实体是不是等于空,非空执行④⑤,获取值并返回值
**如果实体等于 null 或者在.①时 map为null**,都会执行 setInitialValue() 方法,源码如下,
  private T setInitialValue() {
        T value = initialValue();			...............⑦
        Thread t = Thread.currentThread();		...............⑧
        ThreadLocalMap map = getMap(t);		...............⑨
        if (map != null)											...............⑩
            map.set(this, value);
        else															...............十一,输入法只能到10
            createMap(t, value);
        return value;											...............十二
    }

而 ⑦的源码如下:

  /**
     * Returns the current thread's "initial value" for this
     * thread-local variable.  This method will be invoked the first
     * time a thread accesses the variable with the {@link #get}
     * method, unless the thread previously invoked the {@link #set}
     * method, in which case the {@code initialValue} method will not
     * be invoked for the thread.  Normally, this method is invoked at
     * most once per thread, but it may be invoked again in case of
     * subsequent invocations of {@link #remove} followed by {@link #get}.
     *
     * <p>This implementation simply returns {@code null}; if the
     * programmer desires thread-local variables to have an initial
     * value other than {@code null}, {@code ThreadLocal} must be
     * subclassed, and this method overridden.  Typically, an
     * anonymous inner class will be used.
     *
     * @return the initial value for this thread-local
     */
    protected T initialValue() {
        return null;
    }

可以看到,这是一个 protected 方法,也就是说,你可以重写这个方法,并确定你的返回值,比如:

ThreadLocal<T> threadLocal = new ThreadLocal<T>(){
		@Override
		 protected T initialValue() {
	        return t;
	    }
	};

⑧ 获取当前线程对象
⑨ 根据当前线程对象,获取 ThreadLocalMap,源码如下:

   /**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

也就是说,每个线程都会有各自的 ThreadLocalMap,所以,对于要维护的变量而言,它们都会存放在各自线程的 ThreadLocalMap 中,
⑩ map 不为空,设置值
map 为空, 则创建一个 map,源码如下:

 /**
     * Create the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the map
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

我想,源码看到这里,思路也大致明白了。至于 ThreadLocalMap 和 t.threadLocals 就不去看了,感觉没啥好看的,就是一个map,有兴趣大家自己看吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值