java ThreadLocal 自己的一些见解

别人的ThreadLocal

    一开始学的时候就直接去百度了,找了很多的说明和代码样例。
    我个人的学习习惯是先看说明,要精简扼要的那种,让我看了就能理解这是个什么东西,有什么用,然后根据实际的例子去理解。
    这里先复制写网上很容易就可以找到的说明吧。

ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。

    大概差不多都是这样的,可以总结为几点:
    1. ThreadLocal不是Thread
    2. 每个线程都有一个自己的ThreadLocal
    3. 不同的线程的ThreadLocal里面放的是同一个变量的不同副本,从而使得线程之间不会出现资源争抢的情况

然后看了看样例代码,直接就自己写了一个,样例中的资源是一个是整型数据,我觉得那太简单,就直接写了个简单的类,Person有name,age。照着例子搬了过来,结果各种空指针异常。

我的ThreadLocal

我自己写代码测试的过程是这样计划的:
1程序. 写个正常的(或者说有错误的)多线程处理的代码,没有同步机制,也没有ThreadLocal,结果肯定不是预期的
2程序. 改写成同步机制的,结果是对的
3程序. 最后改成ThreadLocal的,结果也是对的,然后把2和3对比对比

代码情况大概如下:
测试类(main方法)
线程类(创建多线程用的)
资源类(Person,被争抢的对象)

样例代码都是一个类把我上面3个类搞定了,测试类本身就实现了奔跑接口,可以当线程用,资源也是基础类型,直接一个成员变量代替了,我觉得看着乱,不够清楚,就直接分成了3个类。

main方法首先是一个资源对象Person p,然后是两个线程对象的实例,接收同一个p到自己的线程内部进行处理。

1程序搞定,
2程序,在线程类的run方法里面给用到p的地方加上同步块,搞定
3程序!!!!!
main方法里创建p的上面创建了一个ThreadLocal对象local,然后把p set进去,然后把local传到线程类里进行操作,线程里之前操作p的地方都替换成了local的get和set。
结果就是一堆的空指针异常。

满脑子想:“同一个变量的不同副本, 我local里面set一个p,然后每个线程里get的p都是之前线程争抢的资源p的一个副本,然后各个线程互不影响。。。。”
然后脑子疼,自己代码跑不通。。。

再就不停的反复的看样例代码,后来也找了几个资源类型不是基础类型的样例,
再就是看ThreadLocal的源码,看看是在哪里创建了怎样的一个副本,是不是只对于基本类型起作用,
好久还是没懂,代码还是没跑通。。。

后来又看到了说是整理好的ThreadLocal的工具类,看到在线程里面new了一个新的资源对象放到了ThreadLocal里面!!!!!

我勒个擦,如果在ThreadLocal里面get不到这个资源,就new一个新的放到里面,而且你第一次get的时候肯定是空 的,如果你不提前set的话。 这岂不是说 每个线程的ThreadLocal里面的对象都是不同的实例,完全的不相干的实例,这线程之间想影响也影响不到啊。

顿时彻底乱了。。。

所谓的ThreadLocal和每个线程绑定,里面放的是资源的副本,搞了半天里面是不是副本不是ThreadLocal本身实现的,而是哥自己手动写的,那我不放副本,那就不是副本了!!!

然后开始回想整个的场景,
当多线程开启的时候,而且多个线程共同享用一个资源的时候,是一个资源,一个(可以理解为单例的,要是多个的话也不用抢了),要考虑这个资源是不是真的需要多个线程共享?
如果这个资源是个计数器,多个线程肯定要共享,要不就记乱了
如果这个资源是个球拍,用来打球的话,完全可以复制几个,自己玩自己的
(比喻不是很恰当啊~~~)

如果这个资源是需要多个线程协同作业,以后还有交集,就是需要共享的,要用同步机制;如果这个资源多个线程自己用自己的,影响不到他人,那就用ThreadLocal复制几份

同步机制从1程序改成2程序,看着很顺理成章,可是ThreadLocal的复制机制怎么改成第3个程序就绕了。

最后想了想,所谓的线程之间互不影响,本质上和ThreadLocal没有什么关系,而且new的原因,你在两个线程里面new了两个对象,让他们怎么互相影响?
而ThreadLocal的作用是保证在同一个线程里面,get的对象是同一个对象,保证线程里的单例,它的重点是和线程绑定。

而且写代码的时候,最好把ThreadLocal写在线程对象里面,好理解(ThreadLocal本来就是和线程绑定的),像我写在main里面,main也是一个线程啊。

最后:是ThreadLocal和new决定了每个线程都有资源的一个副本,互不影响,确切的说只有new。

可能是我理解有问题,网上的资料都是那么写的,看来看去我还是糊涂,最后自己安慰自己,也不知道对不对, 欢迎大家讨论指正!!

另外:MD真难用

====================================
距离写这篇文章已经很久了,期间也断断续续看了些ThreadLocal的文字,有些感悟,再补充上。
1.ThreadLocal不是解决多线程共享同一资源的问题,而且转换了思路,让每个线程都有了一个属于自己的对象,不再有共享、争抢的问题。顺便说一句真正实现每个线程都有一个对象副本的关键是在set的时候new了一个新的,关键在于new。
2.原理或者说源码的理解,个人写了下面一个表达式吧


Thread.{ThreadLocal.ThreadLocalMap}<ThreadLocal.this, Value>
对象.属性<key, value>

其中
Thread:线程
ThreadLocalMap:ThreadLocal的一个静态内部类,在Thread中作为一个成员变量存在
ThreadLocalMap的key是ThreadLocal.this(当前对象的引用),value即资源的副本,new出来的,每个线程放一个新的(副本),线程间互不影响

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值