`
jaesonchen
  • 浏览: 313025 次
  • 来自: ...
社区版块
存档分类
最新评论

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变量也就无法传递给线程池中的线程。

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. import java.util.concurrent.Executor;  
  2. importjava.util.concurrent.Executors;  
  3.    
  4. public classThreadLocalTest {  
  5.    
  6.     private staticThreadLocal<String> vLocal = newThreadLocal<String>();  
  7.    
  8.     public static voidmain(String[] args) {  
  9.    
  10.         Executorexecutor = Executors.newFixedThreadPool(2);  
  11.    
  12.         // 模拟10个请求  
  13.         for (int i =0; i < 10; i++) {  
  14.            final int flag= i;  
  15.            executor.execute(new Runnable() {  
  16.    
  17.                 @Override  
  18.                public voidrun() {  
  19. //                   vLocal.set(null);  
  20.                  //模拟某一线程改变了ThreadLocal的值  
  21.                    if (flag == 1) {  
  22.                        vLocal.set("set:test");  
  23.                    }  
  24.                    System.out.println(Thread.currentThread().getName()+ ":" + vLocal.get());  
  25.                }  
  26.            });  
  27.        }  
  28.    
  29.     }  
  30. }  



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)。

分享到:
评论

相关推荐

    java ThreadLocal多线程专属的变量源码

    java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多...

    ThreadLocal垮线程池传递数据解决方案.docx

    "ThreadLocal垮线程池传递数据解决方案" ThreadLocal 是Java语言中的一种机制,旨在提供线程内数据的传递解决方案。然而,在实际生产中,线程一般不可能孤立的独立去运行,而是交给线程池去调度处理。这时,...

    局部变量线程安全测试

    由于每个线程都有自己的独立的调用栈,因此,从理论上来讲,局部变量在多线程环境中是线程安全的,因为每个线程都拥有自己独立的一份副本。 然而,实际的情况可能更为复杂。例如,如果局部变量引用了非线程安全的...

    Hibernate用ThreadLocal模式(线程局部变量模式)管理Session

    ThreadLocal并不是线程的本地实现,而是一个线程局部变量,它为每个线程提供了一个变量的副本,确保每个线程都可以独立地操作自己的副本,而不干扰其他线程。因此,ThreadLocal可以帮助我们在多线程环境下为每个线程...

    ThreadLocal原理及在多层架构中的应用

    **线程局部变量(ThreadLocal)是Java编程中一个非常重要的概念,主要用于在多线程环境中为每个线程提供独立的变量副本。ThreadLocal不是一种数据结构,而是一种解决线程间共享数据的方式,它提供了线程安全的局部...

    ThreadLocal应用示例及理解

    **线程局部变量(ThreadLocal)是Java编程中一个非常重要的工具类,它在多线程环境下提供了线程安全的数据存储。ThreadLocal并不是一个变量,而是一个类,它为每个线程都创建了一个独立的变量副本,使得每个线程都...

    ThreadLocal

    ThreadLocal是Java编程语言中的一个类,用于在多线程环境中提供线程局部变量。它是一种特殊类型的变量,每个线程都有自己的副本,互不影响,从而实现线程间数据隔离。ThreadLocal通常被用来解决线程共享数据时可能...

    ThreadLocal_ThreadLocal源码分析_

    4. **注意线程池中的ThreadLocal**:线程池中的线程可能会被重用,若不清理ThreadLocal,可能导致后续任务访问到错误的变量副本。 通过理解ThreadLocal的原理和最佳实践,我们可以更有效地利用它来解决多线程环境下...

    ThreadLocal相关

    ThreadLocal 是 Java 语言中的一种机制,用于提供线程内部的局部变量。在多线程环境下,ThreadLocal 变量可以保证各个线程的变量相对独立于其他线程内的变量。这种机制可以帮助开发者在多线程环境下编写更加简洁、可...

    java中ThreadLocal类的使用

    Java中的`ThreadLocal`类是一个非常实用的工具,它提供了线程局部变量的功能。线程局部变量意味着每个线程都拥有自己独立的变量副本,互不干扰,这在多线程编程中尤其有用,可以避免数据共享带来的同步问题。下面...

    ThreadLocal的几种误区

    在服务器端,线程池的存在可能导致多个用户的请求被分配到同一个线程处理,因此,如果不注意清理,ThreadLocal变量可能会被不同用户访问到,造成数据泄露。 误区三:每个用户访问会有新的ThreadLocal 理论上来讲,...

    ThreadLocal的用处

    ThreadLocal是Java编程语言中的一个...综上所述,ThreadLocal在Java多线程编程中扮演着重要角色,它提供了一种安全、高效的方式来管理线程内的局部变量。了解其工作原理和最佳实践对于编写高质量的并发代码至关重要。

    2、导致JVM内存泄露的ThreadLocal详解

    1. **线程未正确销毁**:如果线程执行完毕后没有正确销毁或者线程池中线程长期存活,而`ThreadLocal`对象又未能及时清除,那么线程内的`ThreadLocalMap`将会持续占用内存,进而可能导致内存泄漏。 2. **...

    InheritableThreadLocal & ThreadLocal

    在Java编程中,线程局部变量(ThreadLocal)和可继承线程局部变量(InheritableThreadLocal)是两种非常重要的工具,它们允许我们在多线程环境中创建独立于线程的局部变量,确保每个线程拥有自己的变量副本,避免了...

    正确理解ThreadLocal.pdf

    `ThreadLocal`是Java平台提供的一种线程局部变量的解决方案,它为每一个使用该变量的线程都提供了独立的变量副本,使得每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。这不同于普通的静态...

    java中ThreadLocal详解

    `ThreadLocalMap`本质上是一个哈希表,它使用了弱引用(Weak Reference)作为键,实现了对线程局部变量的存储。具体来说: - **ThreadLocalMap**:每个线程都有一个关联的`ThreadLocalMap`实例。这个实例负责管理...

    04、导致JVM内存泄露的ThreadLocal详解-ev

    04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、导致JVM内存泄露的ThreadLocal详解_ev04、...

    Java中ThreadLocal的设计与使用

    由于ThreadLocal变量是存储在线程的ThreadLocalMap中,如果线程长时间运行并且不清理ThreadLocal,当ThreadLocal对象被垃圾收集时,其在ThreadLocalMap中的引用将变为"幽灵引用"(弱引用),导致内存泄漏。...

    ThreadLocal 内存泄露的实例分析1

    `ThreadLocal` 是 Java 中用于在单个线程内存储线程局部变量的类,每个线程都有自己的副本,不会互相干扰。`MyThreadLocal` 是 `ThreadLocal` 的子类,用于存储 `MyCounter` 对象。在 `LeakingServlet` 的 `doGet` ...

Global site tag (gtag.js) - Google Analytics