谈一谈对ThreadLocal的理解
-
threadlocal可以实现资源对象的线程隔离,保证线程的封闭性,让每个线程各用各的资源对象,避免竞用引发的线程安全问题
为什么不去用局部变量呢?这样更加可以去做到线程的隔离,因为局部变量变量只在当前方法内有效,无法做到线程内的资源共享
-
thread同时实现了线程内的资源共享
-
其原理是,每个线程内有一个threadlocalmap类型的成员变量,用来存储资源对象
- 调用set方法,就是以threadlocal自己作为key,资源对象作为value,放入当前线程的threadlocalmap集合中
- 调用get方法就是以threadlocal作为自己的key。到当前线程中查找关联的资源值
- 调用remove方法,就是以threadlocal自己作为key,移除当前线程关联的资源值
每创建一个threadlocal对象会有一个有规律的哈希值,会根据哈希值来计算一个索引
threadlocalmap初始大小是16,扩容因子是2/3,扩容就是翻倍
索引冲突了,开放寻址法,从冲突的位置开始向后找下一个空闲的位置
threadlocal中的key为什么要设计成弱引用?
只有键是弱引用,调用了父类的构造方法,继承了弱引用
- thread可能需要长时间运行(如线程 池中的线程),如果key不能再使用,需要在内存不足(gc)时释放其占用的内存
- 但gc仅是让key的内存释放,后续还要根据key是否为null来进一步释放值得内存,释放时机有
- 获取key时发现null key
- threadlocal在进行get时即使key不存在也会将key放进去,值为null
- set key时,会使用启发式扫描,清除临近得null key,启发次数与元素个数,是否发现null key有关
- 启发式扫描,对于传统得要么不清理,会浪费内存,要么全部清理,会扫描真个threadlocalmap占用资源,启发式扫描取中间
- remove时,因为一般使用了threadlocal时都把他作为静态变量,因此gc无法回收
- 获取key时发现null key