ThreadLocal如何做到管理方法不一样进程id的?

lxf2023-12-16 08:00:02

`紧接着续篇:探讨ThreadLocal(一)

这篇大家融合源代码方式来回应续篇文尾的几个问题

  • Q1:ThreadLocal和Thread相互关系究竟如何
  • Q2: 为何每启动一个线程便会启用一次initialValue()呢?

一、实例回望

1.1 自定MyThreadLocal

在回答Q1前,我们首先依据续篇中也了解的ThreadLocal来效仿写一个MyThreadLocal。

public class MyThreadLocal<T>{
    private T t;
    protected T initialValue(){return null;}

    public T get() {
    //如果没有值,则启用initialValue复位一个值
        if (t == null){
            return initialValue();
        }
        return t;
    }
}

随后修改一下ThreadId类,改成刚所写的MyThreadLocal去管理进程Id。

public class ThreadId {
    private static final AtomicInteger nextId = new AtomicInteger(0);
    private static final MyThreadLocal<Integer> threadId = new MyThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return nextId.getAndIncrement();
        }
    };

    public static Integer get() {
        return threadId.get();
    }

    public static void main(String[] args) {
        new Thread(() -> System.out.println(ThreadId.get())).start();
        new Thread(() -> System.out.println(ThreadId.get())).start();
        new Thread(() -> System.out.println(ThreadId.get())).start();
        new Thread(() -> System.out.println(ThreadId.get())).start();
    }
}

看运作结论,发觉跟用ThreadLocal一毛一样。

ThreadLocal如何做到管理方法不一样进程id的?

什么原因,我就用短短的两行编码就实现了ThreadLocal的功效了?其实也不是,大家如下所示修改一下测试程序,MyThreadLocal立刻现出原形。

1.2 根本原因

测试程序就不贴了,立即比照看结果。

ThreadLocal如何做到管理方法不一样进程id的?

ThreadLocal如何做到管理方法不一样进程id的?

1.3 剖析源代码

这时候禁不住更为好奇心了,ThreadLocal如何做到管理方法不一样进程id的?咱们融合get()源代码来寻找一下

ThreadLocal如何做到管理方法不一样进程id的?

这儿我们可以看到冒出2个新的东西 ThreadLocalMap 和 ThreadLocalMap.Entry。这俩实际具体内容先无论,可是对比Map和Map.Entry之间的关系。这俩估计也大差不差。接着看get()

跟大家分享个小窍门:首先看代码注释,前去追源代码才会事半功倍。上图中创作者告诫我们:用这种方法回到现阶段进程的thread-local自变量数值。如果这些自变量并没有值,这样就会启用initialValue()回到一个初值。换句话说每一个进程都有一个叫thread-local的自变量咯?咱们就确认一下Thread中是否存在这一自变量。发现这个同样存在,但它并不是ThreadLocal,反而是ThreadLocalMap。

ThreadLocal如何做到管理方法不一样进程id的?

那快来看看ThreadLocalMap和ThreadLocal又是如何个事吧。首先看关系网,ThreadLocal含有个内部类ThreadLocalMap,ThreadLocalMap中还套了个Entry类。

ThreadLocal如何做到管理方法不一样进程id的?

再看源码:

ThreadLocal如何做到管理方法不一样进程id的?

我勒个去,Entry继承WeakReference插口,泛型也是ThreadLocal。此后大家梳理一下Thread和ThreadLocal之间的关系。

1.4 汇总

ThreadLocal如何做到管理方法不一样进程id的?

1.4.1 ThreadLocal和Thread相互关系

从他们讲解的数据看,ThreadLocal和Thread中间没有直接关联。非要说,有的话还可以。由于ThreadLocal是ThreadLocalMap的key。

1.4.2 为何每启动一个线程便会启用一次initialValue()呢?

其实大家汇总穿上图的关联后,正在看这种情况的时候会如梦初醒。而且每个进程都有各自的ThreadLocalMap去存放value。每一个进程在启用ThreadId.get()时,都因为自已的ThreadLocalMap里没有value,而启用initialValue().因而虽然不同类型的进程共用一个ThreadLocal做为key,但由于ThreadLocalMap不一样,二者之间互不干涉。

最终我了解了原先ThreadLocal不判空,我们可以通过它所提供的get()实际是提的Entry的value,它他也是做为key存有Map里的。那时候使用上我们不需要关注ThreadLocal的结构完成小细节,如果通过它所提供的set()/get()就可实际操作进程本地变量。是否特别像实体类的感觉了。封装形式内部实际完成,给予接口调用。

续篇大家然后讨论:为何ThreadLocal能解决线程安全问题?Threadlocal为什么使用弱引用?ThreadLocal有什么适用场景,要注意什么难题?

本站是一个以CSS、JavaScript、Vue、HTML为中心的前端开发技术网址。我们的使命是为众多前端工程师者提供全方位、全方位、好用的前端工程师专业知识和技术服务。 在网站上,大家可以学到最新前端开发技术,掌握前端工程师最新发布的趋势和良好实践。大家提供大量实例教程和实例,让大家可以快速上手前端工程师的关键技术和程序。 本站还提供了一系列好用的工具软件,帮助你更高效地开展前端工程师工作中。公司提供的一种手段和软件都要经过精心策划和改进,能够帮助你节约时间精力,提高研发效率。 此外,本站还拥有一个有活力的小区,你可以在社区里与其它前端工程师者沟通交流技术性、交流经验、处理问题。我们坚信,街道的能量能够帮助你能够更好地进步与成长。 在网站上,大家可以寻找你需要的一切前端工程师网络资源,使您成为一名更加出色的网页开发者。欢迎你添加我们的大家庭,一起探索前端工程师的无限潜能!