美文网首页
ThreadLocal

ThreadLocal

作者: lsh的学习笔记 | 来源:发表于2020-04-30 11:54 被阅读0次

    从使用说起

    ThreadLocal<String> name = new ThreadLocal();
    ThreadLocal<String> school = new ThreadLocal();
    name.set("张三");
    System.out.println(name.get());
    school.set("张三");
    System.out.println(school.get());
    

    从示例代码可以看出,一个ThreadLocal对象只能存储一个数据,如果想存储多个数据,就需要创建多个ThreadLocal对象。

    看看源码

    class Thread {  
        //内部持有ThreadLocalMap  
        ThreadLocal.ThreadLocalMap threadLocals;
    }
    // ThreadLocal 类
    // get 方法
    public void set(T value) {
        Thread t = Thread.currentThread();
        // 注意这个ThreadLocalMap是从当前Thread对象中获取的;
        ThreadLocalMap map = getMap(t);
        if (map != null)
            // 注意这里的key,传的是this;
            map.set(this, value);
        else
            createMap(t, value);
    }
    
    // 从线程中获取 Map
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
    
    // get 方法
    public T get() {
        Thread t = Thread.currentThread();
        // 从当前线程中获取 Map;
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            // 根据 key 获取 value;
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    
    // 类似,但不是 HashMap,注意构造器;
    static class ThreadLocalMap {
        // 内部保存数据的数组
        private Entry[] table;
        // Map的大小
        private int size = 0;
    
        // 构造器的key,写死存储的Entry的key为ThreadLocal类型;
        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);
        }
    
        // set方法也限制死了 key;
        private void set(ThreadLocal<?> key, Object value) {
            // 省略代码
        }
    
        static class Entry extends WeakReference<ThreadLocal<?>> {
            // 关联 ThreadLocal 对象
            Object value;
            // 注意这个构造器,默认传的key就是ThreadLocal对象
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
    }
    

    数据结构

    从上面的源码,我们可以分析得:当前线程 Thread 对象内部有一个类似 HashMap 的类,这个类的Entry 保存着当前线程的数据,Entry 的 key 是ThreadLocal对象,value 是用户 set 的值。

    如果画图的话,就是如下这张图:

    1

    内存泄露

    使用线程池的时候,线程Thread对象结束是不会销毁的,会再次使用的就可能出现内存泄露 。(在web应用中,每次http请求都是一个线程,tomcat容器配置使用线程池时会出现内存泄漏问题)。而且容易造成数据污染

    解决

    每次使用后在finally块remove掉。

    相关文章

      网友评论

          本文标题:ThreadLocal

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