首页 > 其他分享 >ThreadLocal是什么?有哪些应用场景?

ThreadLocal是什么?有哪些应用场景?

时间:2023-12-24 23:55:05浏览次数:36  
标签:map 场景 thread 哪些 ThreadLocalMap value ThreadLocal 线程

大家好,我是joker,希望你快乐。

多线程情况下操作共享变量会产生线程安全问题,需要进行线程间同步,但是并不是所有的情况都是多线程去操作共享变量,有些线程是无状态的只进行操作处理,不涉及共享数据操作,所以就需要threadlocal登场了。

threadlocal是什么?

threadlocal根据命名来看,分为两部分:thread,local,线程,本地的,私有的。通过源码中的注释This class provides thread-local variables可以看出threadlocal这个类提供线程本地变量,作为一个线程内的全局变量。

threadlocal源码分析

下面通过代码进行分析,先来看一个类图:

通过类图可以看出,ThreadLocal依赖于ThreadLocalMap,Thread通过threadLocals属性与ThreadLocalMap组成1:1的组合关系。

Thread的私有数据存储在ThreadLocalMap内。

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 map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
    }

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

Thread中的threadLocals属性:

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

ThreadLocalMap结构比较多,只取了一部分:

    static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

        /**
         * The initial capacity -- MUST be a power of two.
         */
        private static final int INITIAL_CAPACITY = 16;

        /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         */
        private Entry[] table;

可以看到ThreadLocalMap中维护了一个Entry类型数组,用于存储最终的数据,可以先把ThreadLocalMap认为是一个hashmap,还是有很多不同,下次再做比较。

简单做一个总结,Thread的私有变量是存储在自身上的,类型为一个ThreadLocal.ThreadLocalMap的变量,ThreadLocal是一个工具类,用于去维护线程的本地变量。

threadlocal的应用场景

通过上面的分析,可以看出ThreadLocal是一个线程安全,线程私有的,线程生命周期内的全局变量。

通过这些优势特点,可以看出ThreadLocal是线程安全的,避免某些情况需要考虑线程安全进行同步带来的性能损失。

线程生命周期内的全局变量,可以作为一个上下文信息,在整个线程的运行周期内共享数据。

threadlocal可能产生的问题,如何避免

map的key为ThreadLocal实例,key使用了弱引用,所以当把ThreadLocal实例设置为null后,没有任何强引用指向原来的ThreadLocal实例,所以ThreadLocal实例就可以顺利被GC回收。

仍然会造成内存泄漏问题,虽然key为弱引用类型,ThreadLocal能被及时回收,但是value却依然存在内存泄漏问题。ThreadLocal实例的引用设置为null后,没有任何强引用指向原来的ThreadLocal实例,ThreadLocal实例就可以被GC回收,ThreadLocal实例被回收后,value永远不会被访问到,所以存在内存泄漏问题。threadLocals对象中的Entry对象不再使用后,如果没及时清除Entry对象,而程序自身也无法通过垃圾回收机制自动清除,就可能导致内存泄漏。

  • 如何解决

1. 每次用完ThreadLocal都记得调用remove()方法清除数据

2. 将ThreadLocal变量尽可能的定义成static final

  • 内部优化:

1. 调用set()方法时,会采样清理,全量清理,扩容时还会继续检查

2. 调用get()方法时,没有直接命中,向后唤醒查找时会进行清理

3. 调用remove()方法时,除了清理当前Entry,还会向后继续清理

标签:map,场景,thread,哪些,ThreadLocalMap,value,ThreadLocal,线程
From: https://www.cnblogs.com/Crazy_Joker/p/17921778.html

相关文章

  • 人工智能和云计算带来的技术变革:从人工智能的应用场景到云计算的使用案例
    1.背景介绍人工智能(ArtificialIntelligence,AI)和云计算(CloudComputing,CC)是当今最热门的技术趋势之一,它们在各个领域中发挥着重要作用。人工智能是指一种能够模拟人类智能的计算机系统,包括学习、理解自然语言、识别图像、决策等功能。云计算则是一种基于互联网的计算资源共享和......
  • 使用代理IP可以解决哪些网络问题?
    随着互联网技术和科技的发展,在上网的时候使用代理ip的使用人数也越来越多,因为业务的需求需要使用代理ip的应用范围越来越多,那么使用代理IP可以解决哪些网络问题?接下来小编就给大家介绍一下:1.个人信息不安全用户正常上网时,一般都是使用自己设备本地IP地址进行网络请求,有时候会造成隐......
  • 服务器出现大量TIME_WAIT 、CLOSE_WAIT状态的原因有哪些
     一、服务器出现大量CLOSE_WAIT状态的原因CLOSE_WAIT状态,它是TCP四次挥手的第二次挥手被动关闭方的状态。当服务端出现大量CLOSE_WAIT状态的连接的时候,说明服务端的程序没有调用close函数关闭连接。二、服务器出现大量TIME_WAIT状态的原因TIME_WAIT状态,它是TCP四次挥......
  • JVM虚拟机系统性学习-JVM调优实战之内存溢出、高并发场景调优
    调优实战-内存溢出的定位与分析首先,对于以下代码如果造成内存溢出该如何进行定位呢?通过jmap与MAT工具进行定位分析代码如下:publicclassTestJvmOutOfMemory{publicstaticvoidmain(String[]args){List<Object>list=newArrayList<>();for(int......
  • DDoS攻击背后的动机有哪些,如何通过其他手段根本解决这个问题?
    在数字经济时代,随着云计算+AI+5G成新趋势,人们对生活方式逐渐发生改变的同时,随之而来的网络安全威胁也日益严重!DDoS攻击是比较常见的主要攻击手段,相较于传统的DDoS,现在的DDoS攻击势头更为猛烈,屡禁不止,其破坏性也不容小觑。那么导致攻击频发一般是什么原因呢,为什么有的人会有经常遇到......
  • JAVA同城外卖跑腿团购到店跑腿多合一系统都有哪些功能?
    随着移动互联网的迅速发展和普及,同城外卖跑腿团购到店跑腿多合一系统越来越受到用户的青睐。这种系统通过集成了多种服务功能,包括外卖点餐、跑腿代购、团购活动以及到店服务等,使用户能够更加方便快捷地满足自己的需求。本文将以JAVA为开发语言,详细介绍同城外卖跑腿团购到店跑腿多合......
  • JAVA开发同城外卖跑腿团购到店跑腿多合一系统源码有哪些功能?
    随着互联网的普及和快速发展,传统行业与互联网的结合已经成为一种趋势。同城外卖跑腿团购到店跑腿多合一系统就是这种趋势下的产物。该系统通过JAVA开发,集成了外卖点餐、跑腿代购、团购活动以及到店服务等多项功能,为用户提供了便捷、高效的服务体验。本文将详细解析JAVA开发同城外卖......
  • RocketMQ的特性介绍和常用的业务场景
    RocketMQ(ApacheRocketMQ)是一个开源的分布式消息中间件系统,最初由阿里巴巴开发并捐赠给Apache软件基金会。它是一个可靠、可扩展、高吞吐量、低延迟的分布式消息系统,适用于大规模分布式系统中的消息通信。以下是RocketMQ的一些主要特性和常用场景:特性介绍:分布式架构:RocketMQ采用了......
  • 按马哥教育关于2023版Linux云计算SRE工程师掌握知识类别,你会了哪些?
    模块1:Linux新手快速基础入门模块2:面试必备-企业级Shell脚本编程实战模块3:Linux系统结构、内核、进程进阶模块4:网络管理管理及互联网通信实战模块5:互联网常见服务应用实战模块6:网络安全、加密及安全通信实战模块7:安全加固内核防火墙Iptables模块8:企业级Web-LA/NMP架......
  • RedissonLock 使用场景以及优缺点分析
    RedissonLock是Redisson库提供的一种基于Redis实现的分布式锁。以下是如何使用RedissonLock以及其优缺点:使用RedissonLock:初始化Redisson客户端:Configconfig=newConfig();config.useSingleServer().setAddress("redis://localhost:6379");RedissonClientredisson......