美文网首页
ThreadLocal

ThreadLocal

作者: woodnaonly | 来源:发表于2017-05-19 00:12 被阅读12次

    ThreadLocal是什么

    ThreadLocal是一个关于创建线程局部变量的类。

    通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。而使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。

    本文需要解决一下几个问题

    • 每个线程的变量副本是存储在哪里的?

    • 变量副本是怎么从共享的那个变量赋值出来的?源码中的threadlocal的初始值是什么时机设置的?

    • ThreadLocal是如何实现了多个线程之间每个线程一个变量副本的?它是如何实现共享变量的。

    ThreadLocal机制主要由Entry、ThreadLocalMap、Thread、ThreadLocal这四个类相互协作实现的。


    我们来看set()方法

        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    

    这个方法用当前线程t,去获取实体map,并set,如果没有则Creat


    我们再来看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();
        }
    

    同set方法差不多

    我们来看看**ThreadLocalMap **

    //初始化大小
    private static final int INITIAL_CAPACITY = 16;
    //容器为数组
    private Entry[] table;
    

    Entry

    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;
    
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
    

    Entry的定义很简单,它扩展自ThreadLocal类型的WeakReference类,是一个key-value对类。key是ThreadLocal对象的弱引用,value是线程的内部变量。

    Entry使用弱引用作为key目的是,希望在外部不再需要访问ThreadLocal对象时可以让GC尽快地回收对象,而不必等到线程结束后。

    当GC回收ThreadLocal对象后,再通过Entry.get()获取ThreadLocal对象时返回null,这使得内部能够感知什么时候不需要再持有对value的引用,从而释放Entry对象的引用,进而释放value的引用,这时如果value在外部没有任何引用的话(通常你不应该在外部持有对value的引用),随后被GC回收。这种感知和释放的行为发生在ThreadLocal的get、set、remove操作时。


    通常在Java的世界里,我们不需要关系对象的释放,大部分情况下GC会自动帮我们回收。

    但是如果使用ThreadLocal不当,是有可能导致内存泄漏的。

    ThreadLocal释放内部变量通常在以下时机:

    线程结束后
    显式调用remove
    在调用get、set时,如果探测到ThreadLocal对象的弱引用对象get返回null顺便释放。
    所以,如果线程存活的生命周期很长,特别是和进程一样长的话,就要特别注意防止ThreadLocal引入内存泄漏的风险,在不需要再使用某个线程内部变量时记得显式调用remove清理掉。

    参考
    理解ThreadLocal
    理解Java中的ThreadLocal

    相关文章

      网友评论

          本文标题:ThreadLocal

          本文链接:https://www.haomeiwen.com/subject/xbmexxtx.html