threadLocal遇上线程池导致局部变量变化
这两天一直在查无线app一个诡异的问题,表象是stg的接口返回数据,和线上接口的返回数据不一致。
1、初步判断:有缓存,查看代码后发现缓存时间直邮6分钟,而且同一个接口,其他调用方的返回数据,stg和线上是保持一致的。
2、确认版本后,把线上版本和stg环境的版本号,进行多次check,发现版本是一致的。
3、线上和stg接口的返回数据,来源于我依赖的接口,现在接口stg和线上是不一致,而不是一个有数据一个没数据,判断是调用了不同的接口。了解下来接口会根据不同的版本号返回不同的数据,所以判断有版本控制的appClientVersion这个字段传的不对,安装最新的app包,debug我们的stg环境发现版本是4.0.3没有传错。在各种解释不通的情况下,我只好加上日志,把输入输出打出来。
上线后查看日志发现:我的屌丝android手机居然变成了iphone,版本号也是4.0.1,起初怀疑无线版本号不对,连上Fiddler,并切换线上和stg环境,发现请求的clientInfo没有错,的确是android ,4.0.3的版本,那问题肯定是venus到我们的服务再到我们调用服务之前clientInfo被改动了。查看代码发现,clientInfo信息是从ThreadLocal里面拿的。。。原来拿的是别的线程的内容,怪不得连屌丝机都能升级成高富帅。这就可以解释为什么stg永远好的,线上有问题,因为stg测试的全是4.0.3版本的发布包测的。
我们的版本控制是控制interfaceVersion来控制的,再拿到ThreadLocal里面的内容的时候,我们重新赋值了,所以,这个参数没有问题,而appClientVersion和ClientSystem都没有重新赋值,拿到别的线程的内容后就变成了我们所依赖的接口的老版本,所以返回了不同的数据。
ThreadLocal可以为当前线程保存局部变量,而InheritableThreadLocal则可以在创建子线程的时候将父线程的局部变量传递到子线程中。
如果使用了线程池(如Executor),那么即使即使父线程已经结束,子线程依然存在并被池化。这样,线程池中的线程在下一次请求被执行的时候,ThreadLocal对象的get()方法返回的将不是当前线程中设定的变量,因为池中的“子线程”根本不是当前线程创建的,当前线程设定的ThreadLocal变量也就无法传递给线程池中的线程。
- import java.util.concurrent.Executor;
- importjava.util.concurrent.Executors;
- public classThreadLocalTest {
- private staticThreadLocal<String> vLocal = newThreadLocal<String>();
- public static voidmain(String[] args) {
- Executorexecutor = Executors.newFixedThreadPool(2);
- // 模拟10个请求
- for (int i =0; i < 10; i++) {
- final int flag= i;
- executor.execute(new Runnable() {
- @Override
- public voidrun() {
- // vLocal.set(null);
- //模拟某一线程改变了ThreadLocal的值
- if (flag == 1) {
- vLocal.set("set:test");
- }
- System.out.println(Thread.currentThread().getName()+ ":" + vLocal.get());
- }
- });
- }
- }
- }
pool-1-thread-1:null
pool-1-thread-2:set:test
pool-1-thread-1:null
pool-1-thread-2:set:test
pool-1-thread-1:null
pool-1-thread-2:set:test
pool-1-thread-1:null
pool-1-thread-2:set:test
pool-1-thread-1:null
pool-1-thread-2:set:test
因此,必须将外部线程中的ThreadLocal变量显式地传递给线程池中的线程,或者每个请求来的时候先threadLocal.set(null)。
threadLocal遇上线程池导致局部变量变化的更多相关文章
- ThreadLocal 遇上线程池的问题及解决办法
ThreadLocal 称为线程本地存储,它为每一个使用它的线程提供一个其值(value)的副本.可以将 ThreadLocal<T> 理解成 Map<Thread, T>,即 ...
- 源码角度分析-newFixedThreadPool线程池导致的内存飙升问题
前言 使用无界队列的线程池会导致内存飙升吗?面试官经常会问这个问题,本文将基于源码,去分析newFixedThreadPool线程池导致的内存飙升问题,希望能加深大家的理解. (想自学习编程的小伙伴请 ...
- ThreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别
工作中多处接触到了ThreadPoolExecutor.趁着现在还算空,学习总结一下. 前记: jdk官方文档(javadoc)是学习的最好,最权威的参考. 文章分上中下.上篇中主要介绍ThreadP ...
- hreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别
阅读更多 工作中多处接触到了ThreadPoolExecutor.趁着现在还算空,学习总结一下. 前记: jdk官方文档(javadoc)是学习的最好,最权威的参考. 文章分上中下.上篇中主要介绍Th ...
- Python ThreadPoolExecutor 线程池导致内存暴涨
背景 在有200W的任务需要取抓取的时候,目前采用的是线程池去抓取,最终导致内存暴涨. 原因 Threadpoolexcutor默认使用的是无界队列,如果消费任务的速度低于生产任务,那么会把生产任务无 ...
- 在使用线程池时应特别注意对ThreadLocal的使用
使用ThreadLocal并且有线程池时要特别注意,ThreadLocal是以线程为key的,而线程池里面的线程是会被重新利用的,所以如果有使用线程池并且使用ThreadLocal来保存状态信息时要特 ...
- 009-ThreadPoolExecutor运转机制详解,线程池使用1-newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool
一.ThreadPoolExecutor理解 为什么要用线程池: 1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务. 2.可以根据系统的承受能力,调整线程池中工作线线程的数 ...
- 深入理解Java之线程池(爱奇艺面试)
爱奇艺的面试官问 (1) 线程池是如何关闭的 (2) 如何确定线程池的数量 一.线程池销毁,停止线程池 ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown() ...
- 线程池之ThreadPoolExecutor线程池源码分析笔记
1.线程池的作用 一方面当执行大量异步任务时候线程池能够提供较好的性能,在不使用线程池的时候,每当需要执行异步任务时候是直接 new 一线程进行运行,而线程的创建和销毁是需要开销的.使用线程池时候,线 ...
随机推荐
- php字符编码转换中的iconv与mb_convert_encoding用法
iconv ( 'UTF-8' , 'GBK' , $str ); //将$str字符串 utf-8 编码转换成 gbk: 另外,5.4.0 这个版本起,字符非法时候会返回 FALSE,除非在输出字符 ...
- ubuntu12.04下安装搜狗拼音
Ubuntu 12.04 LTS 版本 由于 Ubuntu 12.04 LTS 自带的 Fcitx 版本较旧,需要先通过 PPA 升级,才能安装下载的 deb 软件包. 1. 点击左上角的图标 ...
- Bean的不同配置方式比较与应用场景
基于XML配置 Bean的定义: 在XML文件中通过<bean>元素定义. Bean的名称: 通过<bean>的id或name属性定义. ...
- HDOj-1425
sort Time Limit: 6000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- Flutter实战视频-移动电商-15.首页_商品推荐模块编写
15.首页_商品推荐模块编写 商品推荐,我们做成可以横向滚动的 分析: 上面是标题,下面是ListView,里面是一个Column, column分三层,第一是图片,第二是价格,第三是市场价格 小细节 ...
- 学习RadonDB源码(二)
1. 为我新的一天没有放弃而喝彩 学习是一件很容易放弃的事情,因为就算是不学,我也能在现在的岗位上发光发热.可是人不就是一个热爱折腾的种群吗? 今天没有放弃不代表明天没有放弃,也许放弃的可能性大于坚持 ...
- (2)ASP.NET Core 依赖关系注入(服务)
1.前言 面向对象设计(OOD)里有一个重要的思想就是依赖倒置原则(DIP),并由该原则牵引出依赖注入(DI).控制反转(IOC)及其容器等老生常谈的概念,初学者很容易被这些概念搞晕(包括我在内),在 ...
- 336. Palindrome Pairs(can't understand)
Given a list of unique words, find all pairs of distinct indices (i, j) in the given list, so that t ...
- Unity3D 性能优化
Unity3D 性能优化 一.程序方面 01.务必删除脚本中为空或不需要的默认方法: 02.只在一个脚本中使用OnGUI方法: 03.避免在OnGUI中对变量.方法进行更新.赋值,输出变量建议在Upd ...
- 51nod1093(推公式&找規律)
題目鏈接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1093 題意:中文題誒- 思路:xjb 一開始死活想不出怎麼將一 ...