1. ThreadLocal是Java中所提供的
线程本地存储
机制,可以利用该机制将数据缓存在某个线程内部,该线程可以在任意时刻、任意方法中获取缓存的数据(局部变量)
2. ThreadLocal底层是通过
ThreadLocalMap
来实现的,每个Thread对象(注意不是ThreadLocal
对象)中都存在1个ThreadLocalMap,Map的key为ThreadLocal对象,Map的value为需要缓
存的值
3.
如果在线程池中使用ThreadLocal会造成
内存泄漏
,因为当ThreadLocal对象使用完之后,应该
要把设置的key,value,也就是Entry对象进行回收,但线程池中的线程不会回收,而线程对象
是通过强引用指向ThreadLocalMap,ThreadLocalMap也是通过强引用指向Entry对象(key是弱引用
),线程
不被回收,Entry对象也就不会被回收,从而出现内存泄漏,解决办法是,在使用了ThreadLocal对象之后,手动调用ThreadLocal的remove方法,手动清除Entry对象
4. ThreadLocal经典的应用场景就是连接管理(1个线程持有
1个连接,该连接对象可以在不同的方法之
间进行传递,线程之间不共享同1个连接)
具体的应用场景:
- Spring的事务主要是ThreadLocal和AOP去做实现的
-
代码中云主机的创建日期不对了,排查下来是
SimpleDataFormat
的锅,当时我们使用SimpleDataFormat的parse()方法,内部有一个Calendar对象,调用SimpleDataFormat的parse()方法会先调用Calendar.clear(),然后调用Calendar.add(),如果一个线程先调用了add()然后另一个线程又调用了clear(),这时候parse()方法解析的时间就不对了。其实要解决这个问题很简单,让每个线程都new 一个自己的
SimpleDataFormat
就好了,但是1000个线程难道new1000个SimpleDataFormat
?所以当时我们使用了线程池加上ThreadLocal包装
SimpleDataFormat
,再调用initialValue让每个线程有一个SimpleDataFormat
的副本,从而解决了线程安全的问题,也提高了性能。