threadLocal的分享

本文分析了一款应用中书城首页广告解锁书籍的Free标识显示不稳定的问题。通过对线程池和ThreadLocal的深入研究,发现了InheritableThreadLocal在多线程环境下导致的数据一致性问题,并提出了解决方案。

问题描述:

1、书城首页的书明明是广告解锁的,但是没有free标识,经过多次接口请求得出结论,相同的请求参数,有时会展示出free标识,有时不会展示free标识

问题分析:

1、长时间分析也没有得出结论,因为通过redis和mongodb的查询,所有步骤都能查出对应的数据(该有free的就应该有,没有的就没有),(其实可以使用其他工具排查数据的,例如:arthas,但是当时线上系统没有这个工具)

2、无意发现在线程池的execute方法中使用了MediaHolder这个类,这个类中使用了InheritableThreadLocal,然后就想到线程池中使用ThreadLocal会有些问题

解决:

1、在线程池中重新设置该值,在功能结束时,注销threadLocal

2、以方法的入参形式传递下去,但是这个功能使用media的地方嵌套层次比较深,需要修改的方法太多,最后还是选用第一种方式

3、建议:在线程池中如果使用threadLocal的话,最好在线程池外获取,并在线程池内的方法中重新赋值

原理:

  1. 问题引出:media和media2的值一样么?不一定

1、MediaHolder中使用的ThreadLocal是inheritable类型的(可继承的)

2、也就是说使用了可继承的threadLocal会让线程池中的Thread会复制InheritableThreadLocal,

线程初始化时:

3、使用get方法时,实际使用的是InheritableThreadLocal的get方法,而该类是继承ThreadLocal,重写了getMap方法,返回的ThreadLocalMap是inheritableThreadLocals属性。

注:ThreadLocal中有两个属性的类型是ThreadLocalMap类型:threadLocals和inheritableThreadLocals

4、线程池中如果使用threadLocal的get方法时和线程池外获取的结果可能不一样,

5、线程池创建work,work是一个线程,不断的获取任务,并执行任务,也就是说同一个work可以执行多个任务且任务的ThreadLocal都是一样的。

下图是创建核心worker,其中workQueue.offer(command)就是将任务放到队列中,后续可能会启动非核心work。

在addWorker()方法中有t.start()方法就是开始执行这个线程

下图是核心worker工作的开始

下图是worker不停获取任务方式:1、从firstTask中获取任务,2、从任务队列中获取任务

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值