Java并发之ThreadLocal源码分析(第二篇:添加元素)

前言

    两个与添加元素相关的方法,initialValue()用于初始化一个默认值,set()用于添加一个元素 

 

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

用于添加一个元素的方法,传入的参数是需要保存的Value对象,即所谓的线程局部变量

1、获取当前线程

首先获取调用set()方法的当前Thread对象,并由局部变量t保存

2、获取当前线程持有的ThreadLocalMap对象

接着将当前Thread对象t传入到getMap()方法中,get()方法会返回一个ThreadLocalMap对象,ThreadLocalMap对象是一个哈希表结构的容器,每个Thread对象都会持有一个ThreadLocalMap对象,

3、检查是否成功获取到当前线程持有的ThreadLocalMap对象

getMap()方法有可能返回null,当返回null时,说明Thread对象负责持有的ThreadLocalMap对象还没有创建,所以这里对map进行了判断,分别对两种情况做了不同的业务逻辑

a、当map不等于null时,说明Thread持有的ThreadLocalMap对象已经创建,直接调用ThreadLocalMap对象的set()方法添加一个元素,传入的第一个参数是Key对象,第二个参数是Value对象,此处我们传入的Key对象是当前ThreadLocal对象,Value对象则是方法中传入的T类型的对象

b、当map为null空,则会调用一个createMap()方法用于创建ThreadLocalMap对象,createMap()方法接受的第1个参数是当前Thread对象(注意此处是线程对象,不是ThreadLocal对象),第2个参数是T类型的对象value(线程局部变量,即元素),createMap()方法创建负责缓存key-value对象的容器对象,即ThreadLocalMap对象,它的结构是哈希表,底层是数组,解决哈希冲突用了单链表,而我们添加进去的T类型的对象(元素),将作为该哈希表ThreadLocalMap对象的第一个Entry元素(key-value)中的value,其中的key就是当前ThreadLocal对象

 

initialValue()方法分析

    protected T initialValue() {
        return null;
    }

用于初始化一个默认Value值的方法,一般我们都会重写该方法,注意它是protected修饰

initialValue()方法的返回值就是我们要存储的线程局部变量对象(元素),第一次调用ThreadLocal的get()方法(第三篇:获取元素)的时,initialValue()方法会返回一个Value对象

 

getMap()方法分析

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

用于返回Thread对象持有的ThreadLocalMap对象,传入的参数是Thread对象,一般我们都会传入当前线程

返回的数据类型是ThreadLocalMap,ThreadLocalMap作为静态内部类位于ThreadLocal类中

 

Thread对象持有的threadLocals

    ThreadLocal.ThreadLocalMap threadLocals = null;

可以清楚的看到ThreadLocalMap是ThreadLocal中的一个静态内部类

 

createMap()方法分析

 

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

用于为Thread对象创建持有的ThreadLocalMap对象的方法,传入的第1个参数为Thread对象,传入的第2个参数为Value(第一次保存的线程局部变量)

 

 

总结

1、通过重写ThreadLocal的initialValue()方法,我们可以设置一个默认的线程局部变量对象,好处是,我们在创建ThreadLocal对象时,即保存了一个线程局部变量

2、第一次调用ThreadLocal对象的get()方法时(此时未通过set设置过线程局部变量对象),initialValue()方法返回的线程局部变量对象会存储在一个哈希表(ThreadLocalMap)中

3、通过ThreadLocal的set()方法我们可以添加一个以ThreadLocal对象为key,线程局部变量对象为value的元素到ThreadLocalMap对象中,因ThreadLocalMap对象由当前Thread对象持有,所以set()方法总是需要获得调用它的Thread对象,通过Thread.currentThread()即可得到当前线程对象(在Java虚拟机中,一个Thread对象会对应一个操作系统中的线程)

4、ThreadLocal能实现以Thread为作用域,存储一个对象,依靠的是每个Thread对象持有的一个ThreadLocalMap对象,具体的添加元素过程则是由ThreadLocalMap对象的set()方法完成的

5、当你通过ThreadLocal对象添加一个对象作为线程局部变量时,该对象的引用会存储在Thread对象持有的一个ThreadLocalMap对象中,再由ThreadLocalMap持有的数组对象负责持有

6、Thread对象持有的ThreadLocalMap对象是在ThreadLocal的createMap()方法中创建的!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值