ThreadLocal不调用remove方法会导致业务逻辑错误

简介: ThreadLocal不调用remove方法会导致业务逻辑错误

为什么会导致业务逻辑出错:

当ThreadLocal用于线程池、web应用或者线程被多次重复使用的时候,特别要注意,以web应用为例:

我们都知道web应用很多类都是单例模式,如spring默认注入方式所创建的类就是一个单例,当不同的http请求到达服务器的时候,实际上都是使用了同一个实例,假如该实例使用了全局变量,当请求A修改了这个变量,后面到来的其它请求(此时不管A请求是否结束),如请求B再使用该变量的时候,实际上是被请求A修改过的,这会导致业务逻辑出错,而且很难被发现,这种情况,通常是使用ThreadLocal来解决,因为不同的请求虽然使用了同一个实例,但所使用的线程却不同,但有一点需要特别注意,那就是web容器的线程是重复使用的,web容器使用了线程池,当一个请求使用完某个线程,该线程会放回线程池被其它请求使用,这就导致一个问题,不同的请求还是有可能会使用到同一个线程(只要请求数量大于线程数量),而ThreadLocal是属于线程的,如果我们使用完ThreadLocal对象而没有手动删掉,那么后面的请求就有机会使用到被使用过的ThreadLocal对象,如果一个请求在使用ThreadLocal的时候,是先get()来判断然后再set(),那就会有问题,因为get到的是别的请求set的内容,如果一个请求每次使用ThreadLocal,都是先set再get,那就不会有问题,因为一个线程同一时刻只被一个请求使用,只要我们每次使用之前,都设置成自己想要的内容,那就不会在使用的过程中被覆盖。使用ThreadLocal最好是每次使用完就调用remove方法,将其删掉,避免先get后set的情况导致业务的错误。

例子:

分库 有3个库 db1 db2 db3

web应用使用了线程池 假如有10个线程

request1请求到达web服务端的时候,经过分库逻辑处理后,定位到的是db1,tomcat线程池分配的线程号是thread1,在给予thread1线程的threadlocal.set 保存的数据源是db1

由于tomcat线程池的线程是复用的,request2 恰巧tomcat给予该请求分配到的也是threade1,如果此时针对request2的请求,是不走分库逻辑的,用到的是配置死的db2数据源,那么此时就会导致request2用到的是上个处理请求request1的thread1里面的threadlocal的数据源db1,此时就会导致逻辑错误,找不到相应的表的错误


相关文章
|
3天前
|
缓存 监控 Java
ThreadLocal 源码解析get(),set(), remove()用不好容易内存泄漏
ThreadLocal 源码解析get(),set(), remove()用不好容易内存泄漏
27 1
|
3天前
|
存储 安全 Java
调用链跨线程传递 ThreadLocal 对象对比
说起本地线程专属变量,大家首先会想到的是 JDK 默认提供的 ThreadLocal,用来存储在整个链路中都需要访问的数据,并且是线程安全的。由于在落地全链路压测的过程中,一个基本并核心的功能需求是流量标记需要在整个链路中进行传递,那么线程上下文环境成为解决这个问题最合适的技术。
46 2
调用链跨线程传递 ThreadLocal 对象对比
|
3天前
|
Java
Java 方法(方法的调用机制、方法的传参机制)
Java 方法(方法的调用机制、方法的传参机制)
44 0
|
Java
CheerpJ调用的两种方式
CheerpJ调用的两种方式
204 0
|
设计模式 SQL Java
调用MapperProxy对象|学习笔记
快速学习调用MapperProxy对象
164 0
调用MapperProxy对象|学习笔记
|
程序员 Scala 开发者
函数(方法)的调用机制|学习笔记
快速学习函数(方法)的调用机制。
72 0
函数(方法)的调用机制|学习笔记
为何每次用完ThreadLocal都要调用remove()?
什么是内存泄漏 内存泄漏指的是,当某一个对象不再有用的时候,占用的内存却不能被回收,这就叫作内存泄漏。
|
Java C++
Java中对象为null和调用对象清除方法clear()的不同
Java中对象为null和调用对象清除方法clear()的不同
477 0
|
存储 JavaScript 前端开发
JavaScript继承的几种方法
JavaScript继承的几种方法
113 0
JavaScript继承的几种方法
|
Java 开发者
利用 Object 类解决重复操作|学习笔记
快速学习 利用 Object 类解决重复操作