• ThreadLocal:多线程状态下使用ThreadLocal对全局变量进行数据隔离


    1. 提出问题

    在工作中有这样一个场景,多个方法间调用的时候有大量的参数,功能上也没问题。但是在可读性和美观上还是不够完美,尤其是多个方法都有相同的参数。所以为了近一步优化,可以将这些参数抽出来作为全局参数,值发生变化时对全局变量重新赋值就行了。但是这样做又产生了另一个问题,先看一个栗子。

    public abstract class BaseConntroller {
    
        protected int id = 1;
    
        public abstract void test(int id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    可以看出这是一个抽象类,一个全局变量id初始值是1,一个抽象方法test()

    @RestController
    @Slf4j
    public class DemoController extends BaseConntroller{
    
        @Override
        @GetMapping("test")
        public void test(@RequestParam("id") int id) {
            log.info("线程 = " + Thread.currentThread().getName());
            log.info("id的值 修改前 = " + this.id);
            this.id = id;
            log.info("id的值 修改后 = " + this.id);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这是一个子类继承上面的抽象类(也可以是这个类的全局变量,此栗子是我工作中遇到的真实场景),通过一个GET请求修改全局变量id的值。

    现在发出请求

    第1次GET请求

    2022-09-17 21:45:03.726  INFO 8172 --- [nio-8080-exec-3] xyz.mytch.controller.DemoController      : 线程 = http-nio-8080-exec-3
    2022-09-17 21:45:03.726  INFO 8172 --- [nio-8080-exec-3] xyz.mytch.controller.DemoController      : id的值 修改前 = 1
    2022-09-17 21:45:03.726  INFO 8172 --- [nio-8080-exec-3] xyz.mytch.controller.DemoController      : id的值 修改后 = 2
    
    • 1
    • 2
    • 3

    第2次GET请求

    2022-09-17 21:45:54.998  INFO 8172 --- [nio-8080-exec-5] xyz.mytch.controller.DemoController      : 线程 = http-nio-8080-exec-5
    2022-09-17 21:45:54.998  INFO 8172 --- [nio-8080-exec-5] xyz.mytch.controller.DemoController      : id的值 修改前 = 2
    2022-09-17 21:45:54.998  INFO 8172 --- [nio-8080-exec-5] xyz.mytch.controller.DemoController      : id的值 修改后 = 3
    
    • 1
    • 2
    • 3

    两次请求间服务没有重新启动,可以看出多线程操作同一个全局变量会出现干扰情况。

    2.解决问题

    一个线程操作的时候另一个线程修改了全局变量,出现这种情况肯定是不行的。此时就可以用到一个好东西ThreadLocal对全局变量进行隔离,以实现我的目的。对上面的栗子做个小小的修改。

    public abstract class BaseConntroller {
    
        // 这个可以不用设置初始值,只是为了便于看到修改前后的变化
        protected ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
            @Override
            protected Integer initialValue() {
                return 1;
            }
        };
    
        //protected int id = 1;
    
        public abstract void test(int id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    @RestController
    @Slf4j
    public class DemoController extends BaseConntroller{
    
        @Override
        @GetMapping("test")
        public void test(@RequestParam("id") int id) {
            log.info("线程 = " + Thread.currentThread().getName());
            log.info("id的值 修改前 = " + threadLocal.get());
            threadLocal.set(id);
            log.info("id的值 修改后 = " + threadLocal.get());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    下来又是两个请求,看看效果。

    在这里插入图片描述

    2022-09-17 22:01:34.764  INFO 15880 --- [nio-8080-exec-5] xyz.mytch.controller.DemoController      : 线程 = http-nio-8080-exec-5
    2022-09-17 22:01:34.764  INFO 15880 --- [nio-8080-exec-5] xyz.mytch.controller.DemoController      : id的值 修改前 = 1
    2022-09-17 22:01:34.764  INFO 15880 --- [nio-8080-exec-5] xyz.mytch.controller.DemoController      : id的值 修改后 = 2
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    2022-09-17 22:02:13.637  INFO 15880 --- [nio-8080-exec-7] xyz.mytch.controller.DemoController      : 线程 = http-nio-8080-exec-7
    2022-09-17 22:02:13.637  INFO 15880 --- [nio-8080-exec-7] xyz.mytch.controller.DemoController      : id的值 修改前 = 1
    2022-09-17 22:02:13.637  INFO 15880 --- [nio-8080-exec-7] xyz.mytch.controller.DemoController      : id的值 修改后 = 3
    
    • 1
    • 2
    • 3

    可以看出来吧,问题完美解决。

  • 相关阅读:
    OpenCV实现手势虚拟拖拽
    红杉投资的这家公司押注AI面试
    外汇天眼:投资者关注!Cboe与MSCI发布多样化指数期权和波动率指数
    coreldraw2024版本有哪些新增功能?
    CommonsCollection4反序列化链学习
    Springboot全局配置文件
    js编辑只取修改后的对象的属性和值
    云渲染-体积云【理论基础与实现方案】—— 第一篇
    ARM汇编之数据处理指令
    [计算机效率] 文本编辑工具:Notepad++
  • 原文地址:https://blog.csdn.net/java13245/article/details/126911169