美文网首页
多线程中ThreadLocal踩坑

多线程中ThreadLocal踩坑

作者: 不知名的蛋挞 | 来源:发表于2019-10-28 19:46 被阅读0次

    转自:https://www.jianshu.com/p/66a5dea80070

    ThreadLocal介绍

    ThreadLocal是一个关于创建线程局部变量的类。

    要点:

    • 在当前线程中,任何一个地方都可以访问到ThreadLocal的值。
    • 每个线程里面都有一个ThreadLocalMap变量,初始值为null,这个变量的值由ThreadLocal来维护
    • 当前线程保存在ThreadLocal中的值只能被当前线程访问,一般情况下其他线程访问不到。
    • ThreadLocalMap存储数据方式类似Map的key-value存储方式,只不过ThreadLocal是以当前线程为keyvalue可以为任意类型的值

    问题场景

    项目需要上线一个大版本,此次版本对前端APP新、老版本发起的请求做了不同的加密处理,经过讨论,需要在后台做版本兼容。

    兼容的流程:

    • APP端在请求头里面新增一个字段作为新版本APP的标识,如:varA:123
    • 后端在SpringDispatcherServlet中判断varA是否为空,若不为空则把它放入ThreadLocal变量中
    if (StringUtil.isNotEmpty(varA)){
      ThreadContext.put(ThreadContext.FLAG, varA);
    }
    

    然后在JsonHttpMessageConverter(自定义请求解析类)中,根据varA是否为空来决定采取哪种解密方式来解密请求:

    String flag = ThreadLocal.get(ThreadContext.FLAG);
    if (StringUtil.isNotEmpty(flag)){
      //新版本解密方式
    }else{
      //老版本解密方式
    }
    

    问题描述

    按照上面的兼容流程做完代码更改之后,在本地测试没有问题,但是放在测试环境,由测试人员测试就有问题。

    具体问题描述:

    • 老版本APP发起的请求在后台解密时会进入新版本APP解密方式的判断里面去,但是只是部分请求才会出现此情况

    分析结果

    我们知道,后端应用服务器在处理请求时,会对每一个请求分配一个线程来处理,如果每次来一个请求都去新开一个线程,然后响应请求之后又去销毁线程,这样的结果不仅会增加请求响应时间,而且还会大大提高系统资源消耗。

    所以为了适应高并发请求,在应用服务器端都会使用线程池来处理请求,效果是减少系统资源开销以及加快请求响应时间。

    前面讲到,由于ThreadLocal是以当前线程为key,所以如果前后有两条请求发到后台,并且这两条请求都是使用的线程池里面的同一个线程。并且第一条是新版本APP发过来的带有标识的请求,第二条是老版本APP发过来的不带标识的请求。

    第一条请求把标识存入ThreadLocal变量中,在响应完请求之后没有及时的清理掉ThreadLocal中的值

    当第二条不带标识的请求到来时,由于在SpringDispatcherServlet中做了不为空才把标识放入ThreadLocal中,所以这里就没有更新ThreadLocal中的值,但其实由于前面一个请求响应之后没有清理掉ThreadLocal中的值,所以在JsonHttpMessageConverter中获取当前线程的标识时,还是有值,这样就会进入新版本的解密方式中去。

    <meta charset="utf-8">

    问题处理

    两种方式:

    • SpringDispatcherServlet中不做判空处理,从请求中不管获取到什么值都存入ThreadLocal变量中,以此达到实时更新值的效果

    • 在响应完请求之后移除ThreadLocal中想要移除的值或清空ThreadLocal里面当前线程保存的所有值

    ThreadContext.remove(ThreadContext.FLAG);
    或者清空所有
    ThreadContext.remove();
    

    最后我采取的第二种方式,因为按逻辑是ThreadLocal里面的数据只适合在本次请求中使用,使用完了之后就得清理掉。

    相关文章

      网友评论

          本文标题:多线程中ThreadLocal踩坑

          本文链接:https://www.haomeiwen.com/subject/qsfivctx.html