ThreadLocal 和 InheritableThreadLocal

目录

一 ThreadLocal 是什么

二 ThreadLocal 实现原理

三 ThreadLocal 应用场景

四 InheritableThreadLocal 是什么

五 InheritableThreadLocal 实现原理


一 ThreadLocal 是什么

ThreadLocal 本地线程变量,通过 set() 和 get() 方法来维护局部变量。不同线程之间局部变量彼此隔离,互不影响。

二 ThreadLocal 实现原理

2.1 我们可以先来看看 ThreadLocal、Thread、ThreadLocalMap 之间的关系。

2.1.1 ThreadLocalMap 类属于 ThreadLocal 类的静态内部类

public class ThreadLocal<T> {
    /**
     * ThreadLocals rely on per-thread linear-probe hash maps attached
     * to each thread (Thread.threadLocals and
     * inheritableThreadLocals).  The ThreadLocal objects act as keys,
     * searched via threadLocalHashCode.  This is a custom hash code
     * (useful only within ThreadLocalMaps) that eliminates collisions
     * in the common case where consecutively constructed ThreadLocals
     * are used by the same threads, while remaining well-behaved in
     * less common cases.
     */
    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;
            }
        }
    }
}

 2.1.2 Thread 类持有 ThreadLocal.ThreadLocalMap 变量。

public
class Thread implements Runnable {
    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

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

2.2 set() 和 get() 方法

2.2.1 set() 方法

    /**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {

        /**
         * 获取当前 Thread
         * 通过当前 Thread 获取 ThreadLocalMap
         * 如果 ThreadLocalMap 不为 null,往 ThreadLocalMap 塞值,key 为当前 ThreadLocal
         * 如果 ThreadLocalMap 为 null 创建 ThreadLocalMap
         */
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    /**
     * 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;
    }

当前 Thread 持有 ThreadLocalMap 变量。

2.2.2 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
         * 通过当前 Thread 获取 ThreadLocalMap
         * 如果 ThreadLocalMap 不为 null,通过当前 ThreadLocal 获取 Entry,之后获取值
         * 如果 ThreadLocalMap 为 null,初始化 ThreadLocalMap
         */
        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();
    }

 综上所述:

  1. 每个 Thread 维护着一个 ThreadLocalMap 的引用。
  2. ThreadLocalMap 是 ThreadLocal 的内部类,用 Entry 来进行存储。
  3. 调用 ThreadLocal 的 set() 方法时,实际上就是往 ThreadLocalMap 设置值,key 是ThreadLocal 对象,值是传递进来的对象。
  4. 调用 ThreadLocal 的 get() 方法时,实际上就是往 ThreadLocalMap 获取值,key是 ThreadLocal 对象。
  5. ThreadLocal 本身并不存储值,它只是作为一个 key 来让 Thread 从 ThreadLocalMap 获取 value。

三 ThreadLocal 应用场景

  • 每个线程需要有自己单独的实例。
  • 实例需要在当前线程的多个方法中共享

在实际应用中是,一个 Thread 持有一个 ThreadLocalMap 变量,一个 ThreadLocalMap 可以持有多个 ThreadLocal 对象。由于 ThreadLocalMap 和 Thread 的生命周期一样长,所以,当往 ThreadLocalMap 中设置 ThreadLocal 对象,使用完之后一定要调用 remove()方法,防止内存泄漏。

     /**
     * Removes the current thread's value for this thread-local
     * variable.  If this thread-local variable is subsequently
     * {@linkplain #get read} by the current thread, its value will be
     * reinitialized by invoking its {@link #initialValue} method,
     * unless its value is {@linkplain #set set} by the current thread
     * in the interim.  This may result in multiple invocations of the
     * {@code initialValue} method in the current thread.
     *
     * @since 1.5
     */
     public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

四 InheritableThreadLocal 是什么

为了实现父子线程共享本地变量。

五 InheritableThreadLocal 实现原理

代码演示:

public class InheritableThreadLocalDemo {
    private static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
    public static void main(String[] args) {
        // 主线程
        threadLocal.set("hello world");
        System.out.println("main: " + threadLocal.get());
        // 启动子线程
        Thread thread = new Thread(() -> {
            // 子线程输出父线程的threadLocal 变量值
            System.out.println("子线程: " + threadLocal.get());});
        thread.start();
        threadLocal.remove();
    }
}

运行结果:

从结果上看,子线程确实获取到了主线程的线程变量。

InheritableThreadLocal 源码:

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
    public InheritableThreadLocal() {
    }

    protected T childValue(T var1) {
        return var1;
    }

    ThreadLocalMap getMap(Thread var1) {
        return var1.inheritableThreadLocals;
    }

    void createMap(Thread var1, T var2) {
        var1.inheritableThreadLocals = new ThreadLocalMap(this, var2);
    }
}

源码看  InheritableThreadLocal  继承了 ThreadLocal 之后的 get、set 操作的都是 Thread 的 

inheritableThreadLocals 。

public class Thread implements Runnable {
	
	/* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

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

 父子线程是如何共享线程变量的呢

public class Thread implements Runnable {
	
	/**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, null, gname)}, where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     */
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }


    /**
     * Initializes a Thread.
     *
     * @param g the Thread group
     * @param target the object whose run() method gets called
     * @param name the name of the new Thread
     * @param stackSize the desired stack size for the new thread, or
     *        zero to indicate that this parameter is to be ignored.
     * @param acc the AccessControlContext to inherit, or
     *            AccessController.getContext() if null
     */
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
        
        if (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }

}

在子线程构造器的时候将父线程的线程变量复制一份到了子线程。 

/**
 * Construct a new map including all Inheritable ThreadLocals
 * from given parent map. Called only by createInheritedMap.
 *
 * @param parentMap the map associated with parent thread.
 */
private ThreadLocalMap(ThreadLocalMap parentMap) {
    Entry[] parentTable = parentMap.table;
    int len = parentTable.length;
    setThreshold(len);
    table = new Entry[len];

    for (int j = 0; j < len; j++) {
        Entry e = parentTable[j];
        if (e != null) {
            @SuppressWarnings("unchecked")
            ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
            if (key != null) {
                Object value = key.childValue(e.value);
                Entry c = new Entry(key, value);
                int h = key.threadLocalHashCode & (len - 1);
                while (table[h] != null)
                    h = nextIndex(h, len);
                table[h] = c;
                size++;
            }
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值