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的值。
现在发出请求
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
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
可以看出来吧,问题完美解决。