背景
存入redis的值,可能会出现错误的情况。如果出现错误,接口将会报错。
多个方法一起修改一个公共变量的值,造成数据混乱,导致存入redis中的key值错误
还有每次登陆都会重现创建一个对象,放到公共变量中,遇到并发,对象会被大量地创建,
上一个对象会失去引用,等待垃圾回收器进行回收,导致CPU飙升。
上边公共变量的字符串拼接出现问题,导致下边这张图中的域名中的字符串出现问题。
由上图可知:
**1、使用了线程不安全的ArrayList作为公共变量
2、每次给Arraylist重新赋值的时候都创建了一个新的对象,堆积了大量要回收的旧对象,导致CPU飙升**
(GC会消耗大量CPU和内存来实现垃圾回收)
思路&方案
复现问题:
测试类:
public class ThreadTest { //新建一个list作为成员变量 List<String> testList ; public void updateTestList(){ testList = new ArrayList<>(); testList.add("a01+"); testList.add("a02+"); testList.add("a03+"); testList.add("a04+"); //打印一下看看有什么 System.out.println("updateTestList"+testList); } public void updateTestList2(){ testList = new ArrayList<>(); testList.add("b01+"); testList.add("b02+"); testList.add("b03+"); testList.add("b04+"); //看一下list里有什么 System.out.println("updateTestList2"+testList); } }
客户端:
public class Main { public static void main(String[] args) { ThreadTest threadTest = new ThreadTest(); //开一个多线程测试一下 for (int i = 0; i < 100; i++) { Thread thread = new Thread(new Runnable() { @Override public void run() { threadTest.updateTestList(); threadTest.updateTestList2(); } }); thread.start(); } } }
正常结果只会出现下面两种情况
updateTestList[a01+, a02+, a03+, a04+]
updateTestList2[b01+, b02+, b03+, b04+]
实际上:
注重变量的作用域和生命周期,还要考虑并发量高的时候考虑线程安全,并发的时候还要将对象进行置空。
第一个问题解决方案:
1、在方法之前加 synchronized 关键字。
2、使用ThreadLocal变量。
public class ThreadTest2 { ThreadLocal<List<String>> testList = ThreadLocal.withInitial(()->new ArrayList<>()); public void updateTestList(){ testList.get().removeAll(testList.get()); testList.get().add("a01+"); testList.get().add("a02+"); testList.get().add("a03+"); testList.get().add("a04+"); //打印一下看看有什么 System.out.println("updateTestList"+testList.get()); } public void updateTestList2(){ testList.get().removeAll(testList.get()); testList.get().add("b01+"); testList.get().add("b02+"); testList.get().add("b03+"); testList.get().add("b04+"); //看一下list里有什么 System.out.println("updateTestList2"+testList.get()); } }
结果:
第二个问题(对象重复创建导致CPU和内存飙升)解决方案:
1、使用List的RemoveAll方法将对象进行清除。
现状:
这样就不会持续开辟内存空间。
总结
考虑成本,凡事都要考虑成本。
我们要有无限思维,当只有一个对象的时候我们写的代码不会出现上述问题,但是对象一多就会出现数据错乱的问题,内存飙升的问题,我们的系统不会只有一个用户,所以无限思维是我们必须要考虑的一件事情,考虑并发,考虑将来。而不是只顾眼前。