极速赛车APP下载

Java 线程本地 ThreadLocal 的剖析和小结

电脑杂谈  发布时间:2019-08-31 10:02:13  来源:网络整理

threadlocal static_threadlocal 使用_threadlocal static

ThreadLocal<T>类在Spring,Hibernate等框架中起到了巨大的作用,对于其工作原理,很多网上的文章分析的不够彻底,甚至有些误解。

首先,为了解释ThreadLocal类的工作原理,必须同时介绍与其工作甚密的其它几个类(内部类)

1.ThreadLocalMap

2。Thread

threadlocal static_threadlocal static_threadlocal 使用

可能有人会感觉Thread与ThreadLocal有哪些关系,其实真正的真谛就在Thread类中的一行:

ThreadLocal。ThreadLocalMap threadLocals = null;

其中ThreadLocalMap的定义是在ThreadLocal类中,真正的引用却是在Thread类中

极速赛车APP下载那么ThreadLocalMap究竟是哪个呢?

可以发现这个类必须是一个Map,JDK的解释是

threadlocal static_threadlocal 使用_threadlocal static

ThreadLocalMap is a customized hash map suitable only for maintaining thread local values

接下来的重点是ThreadLocalMap中用于存储数据的entry

static class Entry extends WeakReference<ThreadLocal> {  
	/** The value associated with this ThreadLocal. */  
	Object value;  
	Entry(ThreadLocal k, Object v) {  
		super(k);  
		value = v;  
	}  
}  
从中我们可以看到这个Map的key是ThreadLocal变量,value为用户的值,并不是网上大多数的列子key是泛型的名字以及标志

到这儿,我们就可以理解ThreadLocal究竟是怎样工作的了

1.Thread类中有一个成员变量称作ThreadLocalMap,它是一个Mapthreadlocal static,他的Key是ThreadLocal类

threadlocal static_threadlocal static_threadlocal 使用

2.每个线程拥有自己的申明为ThreadLocal类型的变量,所以这个类的昵称叫'ThreadLocal':线程自己的(变量)

3。此函数生命周期是由该线程决定的,开始于第一次初始(get或者set方式)

4.由ThreadLocal的工作原理决定了:每个线程独自拥有一个变量,并非共享以及拷贝

    /** 
     * @author mxdba 
     * 
     */  
    public class ThreadLocalSample {  
      
        public static void main(String[] args) {  
            ThreadTest test1 = new ThreadTest(10);  
            ThreadTest test2 = new ThreadTest(20);  
            test1.start();  
            test2.start();  
        }  
      
    }  
      
    /** 
     * 此线程有两个ThreadLocal变量,但是由于ThreadLocal是延迟初始的, 
     * 所以在debug时可以看到线程名为“线程20”的线程的ThreadLocalMap中没有thLcal2这个entry 
     * @author mxdba 
     *  
     */  
    class ThreadTest extends Thread {  
          
        public static ThreadLocal<Integer> thLocal = new ThreadLocal<Integer>();  
        public static ThreadLocal<String> thLocal2 = new ThreadLocal<String>();  
          
        public Integer num;  
          
          
          
        public ThreadTest(Integer num) {  
            super("线程" + num);  
            this.num = num;  
        }  
      
        @Override  
        public void run() {  
            Integer n = thLocal.get();  
            if(num != 20) {  
                String s = thLocal2.get();  
            }  
                  
            if(n == null) {  
                thLocal.set(num);  
            }  
            System.out.println(thLocal.get());  
        }  
          
    }  

接下来分析一下源码,就非常知道了

threadlocal static_threadlocal static_threadlocal 使用

    /**  
     * 关键方法,返回当前Thread的ThreadLocalMap  
     * [[[每个Thread返回各自的ThreadLocalMap,所以各个线程中的ThreadLocal均为独立的]]]  
     */  
    ThreadLocalMap getMap(Thread t) {  
            return t.threadLocals;  
        }  

Threadlocal的get方法代码

    public T get() {  
            Thread t = Thread.currentThread();  
            /**  
             * 得到当前线程的ThreadLocalMap  
             */  
            ThreadLocalMap map = getMap(t);  
            if (map != null) {  
                /**  
                 * 在此线程的ThreadLocalMap中查找key为当前ThreadLocal对象的entry  
                 */  
                ThreadLocalMap.Entry e = map.getEntry(this);  
                if (e != null)  
                    return (T)e.value;  
            }  
            return setInitialValue();  
        }  

初始化方法代码

    private T setInitialValue() {  
            /**  
             * 默认返回null,这个方法为protected可以继承  
             */  
            T value = initialValue();  
            Thread t = Thread.currentThread();  
            ThreadLocalMap map = getMap(t);  
            if (map != null)  
                map.set(this, value);  
            else  
                /**  
                 * 初次创建  
                 */  
                createMap(t, value);  
            return value;  
        }  
    /** 
     * 给当前thread初始ThreadlocalMap 
     */  
    void createMap(Thread t, T firstValue) {  
            t.threadLocals = new ThreadLocalMap(this, firstValue);  
        }  
通过上面的探讨threadlocal static,我们看到,ThreadLocal类的使用不仅是拿来解决多线程的难题的,但是还是有很明显的针对性

1.最显著的,ThreadLoacl变量的活动范围为某线程,并且我的理解是该线程“专有的,独自占据”,对该变量的所有操作均有该线程完成!也就是说,ThreadLocal不是用来缓解共享,竞争问题的。典型的应用莫过于Spring,Hibernate等框架中针对多线程的处理了

    private static final ThreadLocal threadSession = new ThreadLocal();    
        
    public static Session getSession() throws InfrastructureException {    
        Session s = (Session) threadSession.get();    
        try {    
            if (s == null) {    
                s = getSessionFactory().openSession();    
                threadSession.set(s);    
            }    
        } catch (HibernateException ex) {    
            throw new InfrastructureException(ex);    
        }    
        return s;    
    }    
这段代码,每个线程有自己的ThreadLocalMap,每个ThreadLocalMap中按照需要初始读取threadSession,这样 的好处就是介于singleton与prototype之间,应用singleton无法解决句柄,应用prototype开销又太大,有了 ThreadLocal之后就好了,对于必须线程“霸占”的数组用ThreadLocal,而该类实例的方式均可以共享。

2.关于内存泄漏:

虽然ThreadLocalMap已经使用了weakReference,但是还是建议能否显示的使用remove方法。


本文来自电脑杂谈,转载请注明本文网址:
http://www.0531mai.com/a/jisuanjixue/article-121197-1.html

    相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    极速赛车APP 极速赛车手机版下载 极速赛车双面盘 极速赛车APP下载 极速赛车手机官网 极速赛车手机版下载 极速赛车双面盘 极速赛车手机官网 极速赛车手机官网 极速赛车手机官网