ThreadLocal的学习

来源:互联网 发布:爱淘宝一元红包链接 编辑:程序博客网 时间:2024/05/22 02:26

对 ThreadLocal 的初步理解

看了很多博客的讲解,我对 ThreadLocal 的理解是:使用 ThreadLocal 的前提是多线程环境,当一个共享变量需要被多个线程共同使用时而又存在线程安全问题时,可以将那个变量封装在 ThreadLocal 中,从而使得每个线程中都有一个副本变量,而且解决线程安全问题。
不加思考的话,看完会觉得自己懂了(嗯,我在说我自己)。可是一段时间后再想起,就可能会有疑问了:前面说”当一个变量需要被多个线程共同使用时而又存在线程安全问题时,可以将那个变量封装在 ThreadLocal 中,从而使得每个线程中都有一个副本变量,而且解决线程安全问题。”既然如此,那么我干嘛不直接在线程中实例化那个变量?这样不也是每个线程中都会有一个副本,这样做甚至不存在线程安全问题。还不用写 ThreadLocal,不是更省事吗?
当时我也懵逼了,对啊。直接在线程中实例化那个对象,连线程安全问题都不会有,不是更好吗。为什么还要那么麻烦去使用 ThreadLocal。后来,想了很久,才意识到自己问题出在哪里。我把前提偷换了。正确的前提是“共享变量”,也就是说这个变量是要供多个线程共同使用的!


共享变量

有一个知识点不知道是不是只有我才忽略了。那就是为什么我们要使用共享变量。当我一开始问自己这个问题的时候,我条件反射般的觉得这是很废的问题。但是仔细想想,这个问题很重要。理解了这个问题,就能明白为什么我们要使用 ThreadLocal 了。

那为什么要使用共享变量?
不同的场景有不同的目的:
一种情况是,共享变量起到的作用是让多个线程之间能够进行通信。像消费者模型中,当队列为空时,消费线程会通知生产线程去生产。当队列不为空时,生产线程会通知消费线程去消费,以及像售票系统中的票数。
还有的情况,就是当一个变量很占内存时而每个线程又需要用到时(例如连接数据库的 Connection 对象,例如 SimpleDateFormat 对象),本身已经是个大对象,如果每个线程都实例化一次对象的话,那内存就会浪费掉很多。所以,将它设为共享变量,以节省内存。
应该还有其他情况吧但我也不知道。(轻喷)


为什么要使用 ThreadLocal?

理解了为什么要使用共享变量后,我们要意识到共享变量可能带来线程安全问题。具体原因就不详细展开了。处理共享变量线程安全问题的方法有很多,而使用 ThreadLocal,是其中一种。
使用 ThreadLocal 的场景,我所知道的一种,是基于在多线程下使用了线程不安全的大对象的情况。前提是多线程,然后因为是大对象,因此将之以共享变量的形式使用,因为线程不安全,因此使用 ThreadLocal,解决线程安全问题。


最后

其实我觉得很多博客都写的挺好的,对 ThreadLocal 实现原理的讲解都很详细。

例如这篇文章:

http://blog.csdn.net/LHQJ1992/article/details/52451136

以及这一篇:

http://blog.csdn.net/lufeng20/article/details/24314381

我觉得要大致看懂 ThreadLocal,主要是要理解 ThreadLocal、ThreadLocalMap 和 Thread 三者的关系:
ThreadLocalMap 定义在 ThreadLocal 中,而又作为 Thread 的一个属性。
ThreadLocalMap 是以 ThreadLocal 对象为 key,以要存储的值为 value。
当我们调用 ThreadLocal 的 get 方法时,先会取得当前线程的 ThreadLocalMap 属性,然后像普通的 map 获取 value 的操作一样,以当前调用 get 方法的那个 ThreadLocal 对象作为为 key,去取得相应的 value。在当前线程中,使用不同的 ThreadLocal 对象去执行 get 方法,就相当于在 map 中用不同的 key 去取不同的 value。


如有写的不对的,请帮忙指出,谢谢。

原创粉丝点击