记对ThreadLocal关于数据隔离的理解

本文通过对比普通变量与ThreadLocal在多线程环境下的表现,深入解析ThreadLocal的工作原理。利用CyclicBarrier同步辅助类,演示了共享变量在线程并发时可能出现的问题,并通过ThreadLocal实现了变量的线程私有化,有效避免了并发修改异常。

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

用普通变量在多线程环境下的例子

public class ThreadLocalTest {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(10,()->{
            System.out.println("每个线程的对于值的初始化完成");
        });
        EasyClass easyClass = new EasyClass();
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            new Thread(()->{
                easyClass.setAnInt(finalI);
                easyClass.setString(String.valueOf(finalI*2));
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"我拿了 int="+easyClass.getAnInt());
                System.out.println(Thread.currentThread().getName()+"我拿了 String="+easyClass.getString());
                System.out.println("=================");
            },String.valueOf(i)).start();
        }
    }
}
class  EasyClass{
    int anInt;
    String string;

    public int getAnInt() {
        return anInt;
    }

    public void setAnInt(int anInt) {
        this.anInt = anInt;
    }

    public String getString() {
        return string;
    }

    public void setString(String string) {
        this.string = string;
    }
}

在这里插入图片描述

  • 我们通过CyclicBarrier放大了线程并发时可能出现的共享变量获取异常的问题,可以看到最后结果都是9和18

下面使用ThreadLocal的方式

public class ThreadLocalTest {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(10,()->{
            System.out.println("每个线程的对于值的初始化完成");
        });
        EasyClass easyClass = new EasyClass();
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            new Thread(()->{
                easyClass.setInt(finalI);
                easyClass.setString(String.valueOf(finalI*2));
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"我拿了 int="+easyClass.getInt());
                System.out.println(Thread.currentThread().getName()+"我拿了 String="+easyClass.getString());
                System.out.println("=================");
            },String.valueOf(i)).start();
        }
    }
}

class EasyClass{
    ThreadLocal<Integer> threadLocal1 = new ThreadLocal<>();
    ThreadLocal<String> threadLocal2 = new ThreadLocal<>();



    public int getInt(){
        return threadLocal1.get();
    }
    public void setInt(int i){
        threadLocal1.set(i);
    }

    public void setString(String q){
        threadLocal2.set(q);
    }
    public String getString(){
        return threadLocal2.get();
    }
}

在这里插入图片描述

  • 这是一个简单的ThreadLocal的例子,能够使想要的变量线程私有化,比如并发共享变量。
  • 这里通过一个CyclicBarrier进行线程阻塞,待全部线程设置了值之后,才对变量进行查看。验证变量线程私有

简单的了解ThreadLocal的用处,那么他是如何实现的?

ThreadLoacl中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);
   }
  ThreadLocalMap getMap(Thread t) {
       return t.threadLocals;
   }

  • 可以看到,set方法先获得当前线程,然后通过getMap方法得到一个map对象。(map对象在哪里?)
  • 如果map不为空,则替换或添加到key为当前ThreadLocal对象 对应的位置

我们继续查看 threadLocals

class Thread implements Runnable {
····
	ThreadLocal.ThreadLocalMap threadLocals = null;
····
}
  • 可以看到 threadLocals是一个ThreadLocalMap 类型的,默认为null,是线程中内置的;
  • 同时这个ThreadLocalMap 是ThreadLocal的一个静态内部类
  • 在这里插入图片描述
  • 在ThreadLocalMap中,也是用Entry来保存K-V结构数据的。但是Entry中key只能是ThreadLocal对象,这点被Entry的构造方法已经限定死了。
  • 同时可以看到Entry继承自WeakReference,但只有Key是弱引用类型的,Value并非弱引用。
  • ThreadLocalMap解决hash冲突的方式是采用线性探测的方式
  • 同时需要注意由于ThreadLocalMap健为弱引用,value不是弱引用,可能导致内存泄漏

在这里插入图片描述
这张图可以比较清除它的一个调用情况,每个线程都有维护自己的Map,如果有ThreadLocal则会放入Entry数组中,这个保证了变量私有化

数据集介绍:多品类农业目标检测数据数据集名称:多品类农业目标检测数据集 图片数量: - 训练集:11,911张图片 - 验证集:422张图片 - 测试集:124张图片 - 总计:12,457张高质量图片 分类类别: 涵盖51个农业相关类别,包括水果(苹果、香蕉、芒果、葡萄)、蔬菜(卷心菜、黄瓜、茄子、菠菜)、坚果(杏仁、腰果、榛子、核桃)、调味作物(辣椒、生姜、大蒜)及肉类(牛肉、鸡肉、猪肉)等,完整覆盖农业生产链关键品类。 标注格式: YOLO格式,包含标准化边界框坐标及类别标签,可直接用于目标检测模型训练。 1. 农业自动化分拣系统 支持开发AI驱动的分拣机器人,精准识别水果成熟度、坚果品类及蔬菜质量,提升加工效率。 1. 智能农场监测 用于无人机或摄像头系统,实时检测作物生长状态、病虫害区域及成熟作物分布。 1. 食品加工质量控制 集成至生产线视觉系统,自动检测原料种类(如肉类分类、坚果筛选),确保加工合规性。 1. 农业科研与教育 为农业院校提供多品类检测基准数据,支持算法研究及教学案例开发。 全链路覆盖 从田间作物(甜玉米、土豆)到加工原料(肉类、坚果),覆盖农业生产-加工全流程检测需求。 标注专业性 YOLO标注经多轮校验,边界框紧密贴合目标,支持复杂场景下的密集目标检测(如混合坚果分拣)。 场景多样性 包含自然光照、阴影遮挡、多角度拍摄等真实农业环境数据,强化模型鲁棒性。 高扩展性 兼容YOLOv5/v7/v8等主流框架,支持快速迁移至分类、计数等衍生任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值