ThreadLocal-共享变量
为什么说ThreadLocal是共享变量?缓存的对象是如何隔离的呢?
并发环境下,在类声明local,每个线程用的都是同一个local,故local对于多线程来说,是共享的。.set()的内部源码是这样的,先获取到当前线程,通过当前线程获取到属于当前线程的ThreadLocalMap,每个entry的key是this(当前local对象),value是缓存的对象。对于每个线程来说,都有各自的ThreadLocalMap,每个ThreadLocalMap是相互隔离的。
ThreadLocal有什么应用场景?
1、缓存事务。并发环境,每个线程的事务缓存在各自的ThreadLocalMap的value中。
2、缓存线程不安全的对象,如SimpleDateFormat,日期格式化对象。
3、缓存Servlet。Servlet是单例的,单例意味着线程不安全,每个请求都有各自的Servlet(包括HttpServletRequest和HttpServletResponse和HttpSession)。使用ThreadLocal保证单例对象的线程安全。
注意:单例意味着该对象线程不安全。
使用ThreadLocal有什么问题?怎么解决?
使用线程池,核心线程数是10个,线程全部执行完毕,10个线程不会销毁。线程不回收,entry也不会回收,从而导致内存泄漏。
注意:heap中的entry中的object是强引用,不会被gc回收。强引用不会被gc回收,必须手动销毁。
local.get()获取缓存的数据,也就是说,缓存对象使用完之后,我们可以手动清除,local.remove(),完美的解决了ThreadLocal内存泄漏问题。
说说ThreadLocal底层的结构。
一个线程下面可以new多个ThreadLocal对象,每个对象分别指向当前线程的ThreadLocalMap,ThreadLocalMap存储n个entry,每个entry的key和value分别是this(调用set()的当前threadLocal实例)和object(自定义类实例)。
经历过具体的有ThreadLocal导致的内存泄漏问题么?
引起内存泄漏问题的因素有两个:1、堆内存的初始大小和最大大小。2、缓存对象存储的数据的最大容量。
缓存对象中定义了一个字节数据,byte[1024*1024],也就是1M,创建一个核心线程数为30的线程池,使用excute将线程的状态修改为running,循环创建30个线程,共计30个ThreadLocalMap,每个map存储了一个对象,共计30M,而我们jvm堆内存设计的初始容量和最大容量是25M,循环到第26次的时候,内存会泄漏。