ThreadLocal理解

本文深入探讨了ThreadLocal的工作机制,解释了它如何为不同线程提供独立的变量副本,特别适用于线程作用域内需要独立变量的场景。通过代码示例展示了ThreadLocal的使用方法,并详细分析了其源码实现,包括get、set方法和内部数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相信了解过handler机制的同学对ThreadLocal都不会陌生,它的作用是为不同线程提供独立的Looper副本。除此之外,以线程为作用域的并且不同线程需要独立的变量的数据都可以采用ThreadLocal。这样可能不太好理解,我们举个例子,假设我们在线程中需要随时随地获取一个对象,我们首先想到的是将这个对象设置成静态的全局变量,这种方法是可以接受的,但是如果每个线程都需要这个对象我们是不是要为每个线程都提供这样一个对象,这样看来就有些不妥,而ThreadLocal恰恰完美的解决了这一点。

用例

private ThreadLocal<Boolean> threadLocal = new ThreadLocal();

onCreate:
		threadLocal.set(false);
        Log.d(TAG, "main: "+threadLocal.get());

        new Thread(new Runnable() {
            @Override
            public void run() {
                threadLocal.set(true);
                Log.d(TAG, "t1: "+threadLocal.get());
            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "t2: "+threadLocal.get());
            }
        }).start();

结果:

2019-06-03 11:04:28.111 14149-14149/com.example.androidplan D/KloseMainActivity: main: false
2019-06-03 11:04:28.112 14149-14172/com.example.androidplan D/KloseMainActivity: t1: true
2019-06-03 11:04:28.116 14149-14173/com.example.androidplan D/KloseMainActivity: t2: null

从日志上可以看到,和预想的结果一样,三个线程的值互不影响,t2线程没有设置所以为null。还有一点,用户可以自定义initialValue()初始化方法,来设置threadLocal初始值。

源码分析

我们先来看一下源码注释

This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its{@code get} or {@code set} method) has its own, independently initialized copy of the variable. {@code ThreadLocal} instances are typically private static fields in classes that wish to associate state with a thread (e.g.,a user ID or Transaction ID).

该类提供线程本地变量。这些变量与普通的对应变量的不同之处在于,每个访问一个变量的线程(通过它的{@code get}或{@code set}方法)都有自己独立初始化的变量副本。{@code ThreadLocal}实例通常是希望将状态与线程(例如,用户ID或事务ID)关联的类中的私有静态字段。

get()

	public T get() {
		//获取当前线程
        Thread t = Thread.currentThread();
        //获取当前线程内部维护的一个ThreadLocalMap对象
        ThreadLocalMap map = getMap(t);
        //如果map为空,说明还没初始化,走setInitiaValue()
        if (map != null) {
        	//根据当前threadlocal对象查询对应的entry
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
            	//得到value并返回
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

	ThreadLocalMap getMap(Thread t) {
		//每个线程内部都维护了一个ThreadLocalMap
        return t.threadLocals;
    }

	private Entry getEntry(ThreadLocal<?> key) {
			//利用散列算法获取下标
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }

	private T setInitialValue() {
		//这里提供给用户自定义初始值
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
        	//插入初始化的value值
            map.set(this, value);
        else
        	//new一个新的map
            createMap(t, value);
        //将自定义的初始化值返回
        return value;
    }

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

	ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
			//初始化一个容量为16的Entry数组
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            //设置阈值
            setThreshold(INITIAL_CAPACITY);
        }

	//阈值为容量的2/3
	private void setThreshold(int len) {
            threshold = len * 2 / 3;
        }

get总结:
首先获取当前线程的ThreadLocalMap,然后根据当前threalocal实例查询对应的Entry,不为空,则返回value,ThreadLocalMap或者Entry为空走初始化方法。

set()

	public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

	private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
			//遍历数组
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
				//找到对应key并替换value
                if (k == key) {
                    e.value = value;
                    return;
                }
				//key==null 添加新的key,value,并清理陈旧数据
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
			
            tab[i] = new Entry(key, value);
            int sz = ++size;
            //如果没有清除陈旧项且超过了阈值,就重新hash
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

	private void rehash() {
			//删除表中所有陈旧项目
            expungeStaleEntries();

           //删除之后还超过阈值的3/4,就进行数组扩容,避免迟滞
            if (size >= threshold - threshold / 4)
                resize();
        }

set总结:
遍历table,如果key相等,替换value,如果key为null,用新key、value替换,同时清理历史key=null的陈旧数据(个人猜想应该是gc之后的),如果超过阀值,就需要再哈希。清理一遍陈旧数据之后 ,如果size还大于等于3/4阀值就把table扩容到原来的两倍,之所以设置为3/4,是为了避免迟滞,最后把原有数据重新哈希散列进新table。

另一个remove方法就不再赘述了。

内容概要:本文系统介绍了基于C#(VS2022+.NET Core)与HALCON 24.11的工业视觉测量拟合技术,涵盖边缘提取、几何拟合、精度优化及工业部署全流程。文中详细解析了亚像素边缘提取、Tukey抗噪算法、SVD平面拟合等核心技术,并提供了汽车零件孔径测量、PCB焊点共面性检测等典型应用场景的完整代码示例。通过GPU加速、EtherCAT同步等优化策略,实现了±0.01mm级测量精度,满足ISO 1101标准。此外,文章还探讨了深度学习、量子启发式算法等前沿技术的应用前景。 适合人群:具备一定编程基础,尤其是熟悉C#和HALCON的工程师或研究人员,以及从事工业视觉测量与自动化检测领域的技术人员。 使用场景及目标:①学习如何使用C#和HALCON实现高精度工业视觉测量系统的开发;②掌握边缘提取、抗差拟合、3D点云处理等核心技术的具体实现方法;③了解工业部署中的关键技术,如GPU加速、EtherCAT同步控制、实时数据看板等;④探索基于深度学习和量子计算的前沿技术在工业视觉中的应用。 其他说明:本文不仅提供了详细的理论分析和技术实现,还附有完整的代码示例和实验数据,帮助读者更好地理解和实践。同时,文中提到的硬件选型、校准方法、精度验证等内容,为实际项目实施提供了重要参考。文章最后还给出了未来的技术演进方向和开发者行动建议,如量子-经典混合计算、自监督学习等,以及参与HALCON官方认证和开源社区的建议。
内容概要:本文介绍了基于WOA-GRU-Attention模型的时序数据分类预测项目,旨在提升时序数据分类准确率,实现智能优化,并提供强泛化能力的分类框架。项目背景指出传统机器学习方法难以处理时序数据的复杂特性,而GRU、注意力机制和WOA的结合能有效应对这些问题。文章详细描述了项目的目标与意义,包括提升分类准确率、实现智能优化、推动元启发式算法的应用等。同时,文中列出了项目面临的挑战及解决方案,如高维数据特征复杂、超参数调优难度大等。项目模型架构由WOA、GRU和注意力机制三部分组成,通过Python代码示例展示了模型的具体实现,包括模型定义、训练过程和WOA优化算法的核心步骤。; 适合人群:具备一定编程基础,尤其是对深度学习、时序数据分析感兴趣的开发者和研究人员。; 使用场景及目标:① 提升时序数据分类准确率,特别是在金融、医疗、智能制造等领域;② 实现模型训练过程的智能优化,避免传统调参的局限;③ 提供具备强泛化能力的时序数据分类框架,支持多行业多场景应用;④ 推动高性能时序模型的工业应用落地,提高智能系统的响应速度和决策质量。; 其他说明:项目不仅实现了工程应用,还在理论层面对GRU结构与注意力机制的融合进行了系统分析,结合WOA优化过程对模型训练动力学展开研究,促进了深度学习与优化算法交叉研究领域的发展。读者可以通过提供的代码示例和链接进一步了解项目的具体实现和应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值