美文网首页
ThreadLocal

ThreadLocal

作者: n油炸小朋友 | 来源:发表于2018-08-11 12:17 被阅读0次

    ThreadLocal,Thead,ThreadLocalMap 三者之间的关系

    • Thread类有一个成员变量 threadLocals
    • 每个线程可能存在多个ThreadLocal
    • ThreadLocalMap 是 ThreadLocal 的一个内部类,threadLocals保存数据的key是ThreadLocal本身

    ThreadLocal的作用

    ThreadLocal为每个线程创建一个单独的变量副本,提供了保持对象的方法和避免参数传递的复杂性。

    应用场景举例

    一个网站进行登录操作,对于每个用户,服务器会为其开一个线程,每个线程中会创建一个ThreadLocal来存用户基本信息等。

    在页面跳转时,需要显示或用到用户信息,这样多线程之间由于用户不同其实并没有联系。用ThreadLocal来存当前用户基本信息,当前线程就可以及时获取想要的数据。

    原理

    ThreadLocal可以看做是一个容器,容器里面存放着属于当前线程的变量。

    ThreadLocal类提供了四个对外开放的接口方法,这也是用户操作ThreadLocal类的基本方法:

    • void set(Object value)
      设置当前线程的线程局部变量的值。

    • public Object get()
      该方法返回当前线程所对应的线程局部变量。

    • public void remove()
      将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收。

    • protected Object initialValue()
      返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次,ThreadLocal中的缺省实现直接返回一个null。

    ThreadLocal类源码:
    主要是对ThreadLocalMap的操作

    /**
     Returns the value in the current thread's copy of this
     thread-local variable.  If the variable has no value for thecurrent 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 map = getMap(t);//获取当前线程对应的ThreadLocalMap
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);//获取对应ThreadLocal的变量值
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();//若当前线程还未创建ThreadLocalMap,则返回调用此方法并在其中调用createMap方法进行创建并返回初始值。
    }
    //设置变量的值
    public void set(T value) {
       Thread t = Thread.currentThread();
       ThreadLocalMap map = getMap(t);
       if (map != null)
           map.set(this, value);//以当前的ThreadLocal做key
       else
           createMap(t, value);
    }
    private T setInitialValue() {
       T value = initialValue();
       Thread t = Thread.currentThread();
       ThreadLocalMap map = getMap(t);
       if (map != null)
           map.set(this, value);
       else
           createMap(t, value);
       return value;
    }
    /**
    为当前线程创建一个ThreadLocalMap的threadlocals,并将第一个值存入到当前map中
    @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对应的ThreadLocal
    public void remove() {
           ThreadLocalMap m = getMap(Thread.currentThread());
           if (m != null)
               m.remove(this);
    }
    

    静态内部类ThreadLocalMap类源码:

    static class ThreadLocalMap {
      //map中的每个节点Entry,其键key是当前实例ThreadLocal,并且还是弱引用,这也导致了后续会产生内存泄漏问题的原因。
     static class Entry extends WeakReference<ThreadLocal<?>> {
               Object value;
               Entry(ThreadLocal<?> k, Object v) {
                   super(k);
                   value = v;
       }
        /**
         * 初始化容量为16,以为对其扩充也必须是2的指数 
         */
        private static final int INITIAL_CAPACITY = 16;
        /**
         * 真正用于存储线程的每个ThreadLocal的数组,将ThreadLocal和其对应的值包装为一个Entry。
         */
        private Entry[] table;
    
    
        ///....其他的方法和操作都和map的类似
    }
    

    相关文章

      网友评论

          本文标题:ThreadLocal

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