最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決ThreadLocal獲取不到值大坑

 更新時間:2023年05月08日 11:09:53   作者:我是小趴菜  
這篇文章主要介紹了解決ThreadLocal獲取不到值大坑

1:問題起因

今天項(xiàng)目上測試環(huán)境,再給領(lǐng)導(dǎo)演示的時候出現(xiàn)了bug,很尷尬。于是我跟前端同學(xué)通過模擬請求,最后發(fā)現(xiàn)在調(diào)一個接口的時候返回了一個 token為空 的錯誤。

但是前端同學(xué)說傳了token了,那為什么還會報token為空的錯誤呢

我們項(xiàng)目使用的JWT生成用戶token,每次請求都要經(jīng)過攔截器校驗(yàn)。因?yàn)樵谡埱蟮臅r候我們經(jīng)常需要用到當(dāng)前用戶登錄的ID,所以我們使用到了ThhreadLocal這個工具類。

Map<String, Claim> claimMap = JwtUtil.verifyToken(headerToken);
if (null == claimMap) {
    throw new GlobalException(ResponseEnums.TOKEN_INVALID_ERROR);
}
//將參數(shù)放入上下文中
Map<String, Object> result = new HashMap<>();
Set<Map.Entry<String, Claim>> entrySet = claimMap.entrySet();
for (Map.Entry<String, Claim> claimEntry : entrySet) {
    result.put(claimEntry.getKey(), claimEntry.getValue().asString());
}
//將用戶ID存到ThreadLocal中,以便后續(xù)的獲取使用
ThreadLocalUtil.getInstance().setContext(result);

這里也貼上ThreadLocalUtil工具類代碼

@Slf4j
public class ThreadLocalUtil {
    private static final ThreadLocal<Map<String, Object>> CONTEXT = new ThreadLocal<>();
    private ThreadLocalUtil() {}
    public static ThreadLocalUtil getInstance() {
        return SingletonHolder.INSTANCE;
    }
    private static class SingletonHolder {
        private static final ThreadLocalUtil INSTANCE = new ThreadLocalUtil();
    }
    public void setContext(Map<String, Object> map) {
        CONTEXT.set(map);
    }
    public static Map<String, Object> getContext() {
        return CONTEXT.get();
    }
    public void clear() {
        CONTEXT.remove();
    }
    public static Integer getUserId() {
        Map<String, Object> context = getContext();
        if(context == null || !context.containsKey(JwtUtil.USER_ID)) {
            throw new GlobalException(ResponseEnums.TOKEN_IS_NULL_ERROR);
        }
        return Integer.parseInt(String.valueOf(context.get(JwtUtil.USER_ID)));
    }
}

2:問題復(fù)現(xiàn)

我們寫一個簡單的測試

public static void main(String[] args) {
    HashMap<String,Object> map = new HashMap<>();
    map.put(JwtUtil.USER_ID,"1");
    ThreadLocalUtil.getInstance().setContext(map);
    System.out.println(ThreadLocalUtil.getUserId());
}

可以看到可以拿到我們設(shè)置的值。

但是如果將ThreadLocal跟Java8的Stream一起配合使用呢?

public static void main(String[] args) {
    HashMap<String,Object> map = new HashMap<>();
    map.put(JwtUtil.USER_ID,"1");
    ThreadLocalUtil.getInstance().setContext(map);
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    //ThreadLocal獲取值放在stream里面執(zhí)行
    list.parallelStream().filter(x -> x.equals(ThreadLocalUtil.getUserId())).collect(Collectors.toList());
}

我們的問題復(fù)現(xiàn)了,報了token為空的錯誤。但是這還是隨機(jī)會出現(xiàn)的情況,并不是每次都會出現(xiàn)。所以導(dǎo)致我們在調(diào)試的時候并沒有出現(xiàn)這個問題

3:分析問題

咋一看并不能知道為什么會這樣,所以我在獲取用戶id的打印了一下日志

看出問題了吧,竟然有三個線程來獲取,因?yàn)槲覀冊O(shè)置值的線程就是main線程,所以前面二個線程獲取到的值就是空的,所以就拋出了異常

所以現(xiàn)在只需要知道這個 ForkJoinPool是在哪就好了,最終在翻看源碼,找到原來就是在jdk8的Stream里面。

這是為什么呢?因?yàn)镴dk8的Stream底層使用了ForkJoinPool線程池,這就導(dǎo)致當(dāng)我們調(diào)用 ThreadLocalUtil.getUserId()的時候,是直接提交到了ForkJoinPool線程池中去了,這時候就會有其它線程去調(diào)用這個方法,所以就拿不到值了

4:如何解決

解決辦法就很簡單了,只需要把ThreadLocalUtil.getUserId()單獨(dú)拿出來執(zhí)行就可以了

public static void main(String[] args) {
    HashMap<String,Object> map = new HashMap<>();
    map.put(JwtUtil.USER_ID,"1");
    ThreadLocalUtil.getInstance().setContext(map);
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    //單獨(dú)拿出來執(zhí)行
    Integer userId = ThreadLocalUtil.getUserId();
    list.parallelStream().filter(x -> x.equals(userId)).collect(Collectors.toList());
}

所以當(dāng)你項(xiàng)目使用到了ThreadLocal的時候,切記要單獨(dú)使用,否則指不定就出現(xiàn)跟我一樣的問題了

以上就是解決ThreadLocal獲取不到值大坑的詳細(xì)內(nèi)容,更多關(guān)于ThreadLocal獲取不到值解決的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JWT整合Springboot的方法步驟

    JWT整合Springboot的方法步驟

    本文主要介紹了JWT整合Springboot的方法步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 基于常用json框架介紹和Jackson返回結(jié)果處理方式

    基于常用json框架介紹和Jackson返回結(jié)果處理方式

    這篇文章主要介紹了基于常用json框架介紹和Jackson返回結(jié)果處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot整合Redisson的兩種方式

    SpringBoot整合Redisson的兩種方式

    這篇文章主要介紹了Spring Boot整合Redisson的兩種方式,方式一直接使用yml配置,方式二創(chuàng)建RedissonConfig配置類,文中通過代碼示例講解的非常詳細(xì),具有一定的參考價值,需要的朋友可以參考下
    2024-04-04
  • MyBatis深入解讀懶加載的實(shí)現(xiàn)

    MyBatis深入解讀懶加載的實(shí)現(xiàn)

    顧名思義,懶加載就是因?yàn)橥祽辛?,懶得加載了,只有使用的時候才進(jìn)行加載。其實(shí),懶加載也加延遲加載,主要以應(yīng)用與Mybatis的關(guān)聯(lián)查詢,按照設(shè)置的延遲規(guī)則,推遲對延遲對關(guān)聯(lián)對象的select查詢
    2022-04-04
  • Java中JDom解析XML_動力節(jié)點(diǎn)Java學(xué)院整理

    Java中JDom解析XML_動力節(jié)點(diǎn)Java學(xué)院整理

    JDOM是一種解析XML的Java工具包。DOM適合于當(dāng)今流行的各種語言,包括Java,JavaScripte,VB,VBScript,Perl,C,C++等。下面通過本文給大家介紹Java中JDom解析XML的方法,感興趣的朋友一起學(xué)習(xí)吧
    2017-07-07
  • java實(shí)現(xiàn)IP地址轉(zhuǎn)換

    java實(shí)現(xiàn)IP地址轉(zhuǎn)換

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)IP地址轉(zhuǎn)換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • springboot+thymeleaf找不到視圖的解決方案

    springboot+thymeleaf找不到視圖的解決方案

    這篇文章主要介紹了springboot+thymeleaf找不到視圖的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java隨機(jī)密碼生成并和郵箱、手機(jī)號匹配

    Java隨機(jī)密碼生成并和郵箱、手機(jī)號匹配

    這篇文章主要介紹了Java隨機(jī)密碼生成并和郵箱、手機(jī)號匹配的相關(guān)資料,需要的朋友可以參考下
    2016-01-01
  • 再也不用怕! 讓你徹底搞明白Java內(nèi)存分布

    再也不用怕! 讓你徹底搞明白Java內(nèi)存分布

    做Java的大都沒有c++ 的那種分配內(nèi)存的煩惱,因?yàn)镴ava 幫我們管理內(nèi)存,但是這并不代表我們不需要了解Java的內(nèi)存結(jié)構(gòu),因?yàn)榫€上經(jīng)常出現(xiàn)內(nèi)存的問題,今天聊一下內(nèi)存的問題,需要的朋友可以參考下
    2021-06-06
  • spring框架下@value注解屬性static無法獲取值問題

    spring框架下@value注解屬性static無法獲取值問題

    這篇文章主要介紹了spring框架下@value注解屬性static無法獲取值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11

最新評論

六枝特区| 白山市| 寿宁县| 泰兴市| 苗栗市| 北流市| 高碑店市| 郁南县| 吴堡县| 秭归县| 米脂县| 集贤县| 西林县| 蕲春县| 桃江县| 井冈山市| 怀安县| 会东县| 龙江县| 蓬莱市| 华蓥市| 阳泉市| 天台县| 遂昌县| 黄石市| 大姚县| 中方县| 福建省| 临朐县| 确山县| 桂林市| 洛南县| 安平县| 天津市| 芷江| 龙海市| 慈利县| 香河县| 高安市| 沁源县| 鹰潭市|