背景
- 学会ThreadLocal的简单使用。
- 学会理解一个事物,是从这个事物的定义和概念开始的。
- 学会问为什么?为什么ThreadLocal存在?它的存在解决了什么问题?
- 学会对比技术,至少培养这样的意识。
核心内容
- ThreadLocal的简单使用
-
例子代码
-
测试代码
-
测试结果
-
代码结果分析
两个线程共用同一个ThreadLocalDemo实例。当其中一个线程,任意一个线程,获取下一个值的时候,会先执行 num.set(num.get() + 1) 这一逻辑,根据结果来看,这个线程打印值是1 。而另一个线程,如果受到影响,那么它的值应该是 2,但是实际打印的也是 1 。
因此,从结果来说,线程之间的对同一个ThreadLocalDemo实例操作是安全,相互之间没有任何影响。
- ThreadLocal是什么?
- 空间换时间。
- 线程独立的私有空间。
- 解决并发问题的新思路。
-
为什么有ThreadLocal?它解决了synchronized性能慢的问题
一般来说,在解决多线程的问题,我们都是上锁。上锁其实可以理解为同步(synchronized)。但是,同步的操作,是一个耗时的操作,为什么呢?当一个线程拿到锁,那么其他所有的线程都必须等,直到这个线程执行完成并释放锁。那么这个过程是非常耗费时间的。所以说,只要使用synchronized,都是耗费时间的。
然而,有的会认为,不一定。有时候使用了synchronized,性能更高。怎么可能?任何一个场景都不可能。
-
ThreadLocal vs synchronized(相对比较)
项目 空间 执行速度 ThreadLocal 大 快 synchronized 小 慢 -
由上表格分析
由上面的表格,推断出。如果内存空间多,那么是完全可以使用ThreadLocal来替代synchronized。如果内存空间少,而且对性能要求不是特别高,那么是可以使用synchronized。
-
使用场景
- 需求:空间资源是稀缺的吗?对执行速度有非常高的要求吗?
- 多线程共享一个变量,这个变量需要线程独享,也就是一个线程修改后,不能影响其他线程。
- 分析这样的业务场景。一个变量在多线程环境下,是线程独享的,还是线程共享。如果在多线程环境中是独享的,则使用ThreadLocal。如果是线程共享,就是一个线程修改了内容,后面的线程可见且在这个新的值基础上再次进行修改,可以使用synchronized或者并发包中的一些原子操作类,原子操作类中也有提供对引用类型的数据操作。
- 注意事项
- 当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
- JDK5.0已经升级。ThreadLocal变成ThreadLocal。void set(T value), T get(T value),T initialValue()
- 简单理解
- 有一个全局的变量比如一个实例,有多个线程,每个线程都会对这个实例的内容进行更改,但是相对于每个线程来说,更改是独立的,就是一个线程的更改不能对别的线程产生影响。
- 使用理解,多个线程持有同一个拥有ThreadLocal属性的实例,每个线程虽然操作的是同一个实例对象,但是这个实例对象中的属性是每个线程私有的,相互之间并不发生影响。可以理解是属性ThreadLocal实例中内部类ThreadLocalMap中存储了当前线程为key, initialValue中的值为对应的值。在使用过程中,当前线程进行获取值,业务处理,在把值放回去。
小结
- ThreadLocal的使用并不重要,如果需要,可以立即查询。就像我们没有必要记忆JDK的API或者其他框架的API一样,使用的时候,查询即可。
- 真正能够从ThreadLocal学到什么,或者说ThreadLocal对自己有怎样的启示,这个才是价值。
- 需要学会对比ThreadLocal和synchronized的优缺点。