• ThreadLocal详解


    一、ThreadLocal

    1、说明

    ThreadLocal 是一个线程局部变量。其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。

    2、使用方法

    ThreadLocal<String> nameThreadLocal = new ThreadLocal<>();
    nameThreadLocal.set(name);
    nameThreadLocal.get()
    • 1
    • 2
    • 3

    3、Request 使用案例

    springMvc中单例controller中定义成员变量 request ,使用@autowired注入时,request就是使用ThreadLocal实现线程安全的。

    1. 在controller中注入的request是jdk动态代理对象,ObjectFactoryDelegatingInvocationHandler的实例.当我们调用成员域request的方法的时候其实是调用了objectFactory的getObject()对象的相关方法.这里的objectFactory是RequestObjectFactory.
    2. RequestObjectFactory的getObject其实是从RequestContextHolder的threadlocal中去取值的.
    3. 请求刚进入springmvc的dispatcherServlet的时候会把request相关对象设置到RequestContextHolder的threadlocal中去.

    参考:在SpringMVC Controller中注入Request成员域 - abcwt112 - 博客园

    4、参考

    ThreadLocal详解

    https://www.jianshu.com/p/3bb70ae81828

    二、InheritableThreadLocal

    1、说明

    ThreadLocal设计之初就是为了绑定当前线程,如果希望当前线程的ThreadLocal能够被子线程使用,实现方式就会相当困难(需要用户自己在代码中传递)。在此背景下,InheritableThreadLocal应运而生。

    2、原理

    创建新的线程时,会调用以下的构造方法。

        public Thread(Runnable target) {
            init(null, target, "Thread-" + nextThreadNum(), 0);
        }
    
    • 1
    • 2
    • 3

    我们沿着构造方法中的init方法,可以找到这样一段代码。就是在这里创建的 inheritableThreadLocals 。

            if (inheritThreadLocals && parent.inheritableThreadLocals != null)
                this.inheritableThreadLocals =
                    ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    
    • 1
    • 2
    • 3

    继续查看 createInheritedMap 方法,里面新建了一个 ThreadLocalMap 对象,其构造方法如下。

    分析代码我们可知,在创建子线程时,会将父线程的 inheritableThreadLocals 复制到子线程的 inheritableThreadLocals 对象。

            private ThreadLocalMap(ThreadLocalMap parentMap) {
                Entry[] parentTable = parentMap.table;
                int len = parentTable.length;
                setThreshold(len);
                table = new Entry[len];
    
                for (int j = 0; j < len; j++) {
                    Entry e = parentTable[j];
                    if (e != null) {
                        @SuppressWarnings("unchecked")
                        ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
                        if (key != null) {
                            Object value = key.childValue(e.value);
                            Entry c = new Entry(key, value);
                            int h = key.threadLocalHashCode & (len - 1);
                            while (table[h] != null)
                                h = nextIndex(h, len);
                            table[h] = c;
                            size++;
                        }
                    }
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3、参考

    InheritableThreadLocal详解
    https://www.jianshu.com/p/94ba4a918ff5

    三、ThreadLocal内存泄漏

    https://blog.csdn.net/qq_25775675/article/details/105731434

  • 相关阅读:
    easyExcel应用
    如何防止重复下单?
    SAP UI5 SimpleForm 控件的 adjustLabelSpan 属性
    【JS逆向 + python模拟获取】今天逆向一个简单的半混淆网站,获取token的生成方法,并用python模拟获取数据
    SSRF漏洞
    【总结】shell 脚本命令执行结果赋值给变量无效
    Prometheus + Grafana 搭建监控仪表盘
    STM32 SPI对存储芯片发送写是能命令后一直忙等待
    鸿蒙搭配前端开发:应用端与WEB端交互
    创业思维和商业模式的区别,从0到1:构建到突破,专业新零售全案策划
  • 原文地址:https://blog.csdn.net/qq_25775675/article/details/125617564