面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?

点击上方Java之间”,选择“置顶或者星标”

你关注的就是我关心的!

640?wx_fmt=jpeg

来源:Java识堂

640?wx_fmt=jpeg

遇到问题

最近一个小伙伴把项目中封装的日期工具类用在多线程环境下居然出了问题,来看看怎么回事吧

日期转换的一个工具类

640?wx_fmt=jpeg

然后将这个工具类用在多线程环境下

640?wx_fmt=jpeg

结果报异常了

640?wx_fmt=jpeg

这个异常就不从源码的角度分析了,写一个小Demo,理解了这个小Demo,就理解了原因

一个将数字加10的工具类

640?wx_fmt=jpeg

然后代码的一部分输出为

640?wx_fmt=png

什么鬼,不是加10么,怎么都输出了28?这主要是因为线程切换的原因,线程陆续将addNum值设置为0 ,3,7但是都没有执行完(没有执行到return addNum+10这一步)就被切换了,当其中一个线程将addNum值设置为18时,线程陆续开始执行addNum+10这一步,结果都输出了28。SimpleDateFormat的原因和这个类似,那么我们如何解决这个问题呢?

解决方案

解决方案1:每次来都new新的,空间浪费比较大

640?wx_fmt=jpeg

解决方案2:方法用synchronized修饰,并发上不来

640?wx_fmt=jpeg

解决方案3:用jdk1.8中的日期格式类DateFormatter,DateTimeFormatter,又不想改项目中用到这个工具类的代码

解决方案4:用ThreadLocal,一个线程一个SimpleDateFormat对象

640?wx_fmt=jpeg

上面的加10的工具类可以改成如下形式(主要为了演示ThreadLocal的使用)

640?wx_fmt=jpeg

现在2个工具类都能正常使用了,这是为啥呢?

原理分析

当多个线程同时读写同一共享变量时存在并发问题,如果不共享不就没有并发问题了,一个线程存一个自己的变量,类比原来好几个人玩同一个球,现在一个人一个球,就没有问题了,如何把变量存在线程上呢?其实Thread类内部已经有一个Map容器用来存变量了。它的大概结构如下所示

640?wx_fmt=jpeg

ThreadLocalMap是一个Map,key是ThreadLocal,value是Object

映射到源码就是如下所示:

ThreadLocalMap是ThreadLocal的一个静态内部类

640?wx_fmt=jpeg

往ThreadLocalMap里面放值

640?wx_fmt=jpeg

从ThreadLocalMap里面取值

640?wx_fmt=jpeg

再回头看一下刚开始的例子,是不是理解的很清楚了呢?


640?wx_fmt=png

最近热文阅读:

1、经典面试题:为什么要把系统拆分成分布式的,为啥要用Dubbo?

2、Java中令人眼花撩乱的数字魔法!

3、使用了eclipse10年之后,我终于投向了IDEA

4、祖传代码,轻则伤筋动骨,重则一命呜呼

5、拼多多面试真题:如何用Redis统计独立用户访问量!

6、Spring中的18个注解,你会几个?

7、阎王爷让我给他做个后台管理系统

8、你不知道的SpringBoot微信点餐系统开源码,实用!

640?wx_fmt=jpeg

关注公众号,你想要的Java都在这里

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值