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

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

你关注的就是我关心的!

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第1张图片

来源:Java识堂

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第2张图片

遇到问题

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

日期转换的一个工具类

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第3张图片

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

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第4张图片

结果报异常了

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第5张图片

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

一个将数字加10的工具类

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第6张图片

然后代码的一部分输出为

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第7张图片

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

解决方案

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

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第8张图片

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

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第9张图片

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

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

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第10张图片

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

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第11张图片

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

原理分析

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

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第12张图片

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

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

ThreadLocalMap是ThreadLocal的一个静态内部类

640?wx_fmt=jpeg

往ThreadLocalMap里面放值

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第13张图片

从ThreadLocalMap里面取值

面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?_第14张图片

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


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都在这里

你可能感兴趣的:(面试官:用过ThreadLocal吗?它保证线程安全的原理是啥?)