ThreadLocal

Posted 静水楼台/Java部落阁

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreadLocal相关的知识,希望对你有一定的参考价值。

一、概述
下面是jdk文档对ThreadLocal的描述。

ThreadLocalMap is a customized hash map suitable only for maintaining thread local values. No operations are exported outside of the ThreadLocal class. The class is package private to allow declaration of fields in class Thread. To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys. However, since reference queues are not used, stale entries are guaranteed to be removed only when the table starts running out of space.

翻译:
ThreadLocalMap仅仅是为了维持线程本地变量值而自定义的hash结构。不会有操作被暴露到ThreadLocal外。
为了应对大对象或存活时间较长的对象,hash表的Entry使用的WeakReferences作为key。
然而,当引用队列不再被使用时,Entry就不再被使用了,必须保证它被移除,仅当hash表用完了空间。


二、使用

ThreadLocal一般都是声明在static变量中的,如果不断的创建ThreadLocal而没有调用其remove方法,将会导致内存泄漏,特别是在高并发的web容器中这么做的时候。


三、应用场景
1.Spring中用来管理数据库资源
2.Struts2中通过ActionContext来获取相应的对象,每个线程获取的都是自己的数据。
3.数据传递
在同一请求中,可以传递数据。一次请求先经过拦截器后再进入controller,在拦截器中需要查询用户信息,而进入了controller之后可能又需要使用该用户信息,这时可以使用ThreadLocal来保存数据,因此一次请求对应的是同一个线程。

四、源码分析

    public T get() {
        // 获取当前线程
        Thread t = Thread.currentThread();
        // 获取当前线程绑定的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        // 获取不到值,则自动为其设置一个初始值并返回。
        return setInitialValue();
    }
    
    public void set(T value) {
        // 获取当前线程
        Thread t = Thread.currentThread();
        // 获取当前线程绑定的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null)
            // 
            map.set(this, value);
        else
            createMap(t, value);
    }
    
    // 获取线程绑定的ThreadLocalMap
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

ThreadLocal并未使用HashMap来作为存储结构,而是重新实现了一个类似于HashMap的Map数据结构
先来看看ThreadLocalMap的实现。

 

初始容量为16,负载因子为2/3。

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

 

五、避免内存泄漏

 

以上是关于ThreadLocal的主要内容,如果未能解决你的问题,请参考以下文章

源代码系列02——ThreadLocal源码分析(基础篇)

java中的ThreadLocal详解及示例代码

ThreadLocal介绍

MyBatis基础:使用java提供的ThreadLocal类优化代码

Java 单线程代码ThreadLocal串值问题

ThreadLocal