问题描述:
1、书城首页的书明明是广告解锁的,但是没有free标识,经过多次接口请求得出结论,相同的请求参数,有时会展示出free标识,有时不会展示free标识
问题分析:
1、长时间分析也没有得出结论,因为通过redis和mongodb的查询,所有步骤都能查出对应的数据(该有free的就应该有,没有的就没有),(其实可以使用其他工具排查数据的,例如:arthas,但是当时线上系统没有这个工具)
2、无意发现在线程池的execute方法中使用了MediaHolder这个类,这个类中使用了InheritableThreadLocal,然后就想到线程池中使用ThreadLocal会有些问题
解决:
1、在线程池中重新设置该值,在功能结束时,注销threadLocal
2、以方法的入参形式传递下去,但是这个功能使用media的地方嵌套层次比较深,需要修改的方法太多,最后还是选用第一种方式
3、建议:在线程池中如果使用threadLocal的话,最好在线程池外获取,并在线程池内的方法中重新赋值
原理:
问题引出: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、从任务队列中获取任务