美文网首页
谈谈对ThreadLocal的理解

谈谈对ThreadLocal的理解

作者: Jerry_dong | 来源:发表于2017-05-24 16:24 被阅读0次

    ThreadLocal是什么?

    ThreadLocal从字面上的理解是本地线程的意思,然而事实上它是共享变量的一份拷贝,所以称之为ThreadLocalvVariable更合适

    ThreadLocal对于多线程数据共享的意义?

    下面举个多线程共享一个对象的例子(理解为单例)

    package com.test.threadLocal;
    
    public class Student {
        
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }   
    
    }
    
    package com.test.threadLocal;
    
    public class MyThread extends Thread {
        
        private Student student;
        
        private String name;
        
        public MyThread(Student student,String name) {
            this.student = student;
            this.name = name;
        }
    
        @Override
        public void run() {
           this.student.setName(name);
           String myName = name;
           try
           {
             Thread.sleep(5000);
           }
           catch (InterruptedException e)
           {
             e.printStackTrace();
           }
           System.out.println("Thread: " + Thread.currentThread().getName()
                    + ", name: " + student.getName() + ", myName: " + myName);
        }
    }
    
    package com.test.threadLocal;
    
    public class Test
    {
        public static void main(String[] args)
        {
            Student student = new Student();
    
            MyThread thread0 = new MyThread(student, "liubei");
            MyThread thread1 = new MyThread(student, "zhangfei");
            MyThread thread2 = new MyThread(student, "guanyu");
            
            thread0.start();
            thread1.start();
            thread2.start();
        }
    }
    

    运行结果

    Thread: Thread-1, name: zhangfei, myName: zhangfei
    Thread: Thread-2, name: zhangfei, myName: guanyu
    Thread: Thread-0, name: zhangfei, myName: liubei

    通过ThreadLocal改造Student代码,获取正确的结果

    package com.test.threadLocal;
    
    public class Student {
        
        private String name;
        
        private static ThreadLocal<String> threadLocal = new ThreadLocal<String>();
    
        public static String getName() {
            return threadLocal.get();
        }
    
        public static void setName(String name) {
            threadLocal.set(name);
        }   
    
    }
    

    运行结果

    Thread: Thread-2, name: guanyu, myName: guanyu
    Thread: Thread-1, name: zhangfei, myName: zhangfei
    Thread: Thread-0, name: liubei, myName: liubei

    ThreadLocal类中重要的方法

    ThreadLocal类的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 t = Thread.currentThread();
            //ThreadLocalMap是ThreadLocal的一个静态内部类,这里从数据结构上可以把ThreadLocalMap理解成HashMap,HashMap的解析会在之后的博客中解释
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    

    ThreadLocal类的getMap和createMap方法

    ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }
    void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    

    Thread类的threadLocals变量

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

    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 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();
        }
    

    ThreadLocal的setInitialValue,initialValue方法

    /**
         * Variant of set() to establish initialValue. Used instead
         * of set() in case user has overridden the set() method.
         *
         * @return the initial 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;
        }
    
    /**
         * 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
         */
    //用来设置初始化的value值,由子类决定是否重写
    protected T initialValue() {
            return null;
        }
    

    对ThreadLocal,ThreadLocalMap和Thread的关系的理解

    简单的说每一个Thread对应的它的一个ThreadLocalMap,而ThreadLocalMap的key就是ThreadLocal,value是对应存储的值。从上述原代码中还可以得知,只要Thread没销毁,就能从ThreadLocalMap中get到你要的东西,换句话说,我们也可以将我们认为重要的信息存进去,其实Struts2中的ActionContext就是这么做的

    synchronized和ThreadLocal的区别

    对于多线程资源共享的问题,synchronized采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

    相关文章

      网友评论

          本文标题:谈谈对ThreadLocal的理解

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