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

1. 提出问题

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

public abstract class BaseConntroller {

    protected int id = 1;

    public abstract void test(int id);
}

可以看出这是一个抽象类,一个全局变量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);
    }
}

这是一个子类继承上面的抽象类(也可以是这个类的全局变量,此栗子是我工作中遇到的真实场景),通过一个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

第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

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

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);
}
@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());
    }
}
下来又是两个请求,看看效果。

在这里插入图片描述

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

在这里插入图片描述

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值