案例15-ArrayList线程不安全,共用全局变量导致数据错乱问题,占用内存情况
创始人
2025-05-29 22:59:47

目录

    • 背景
        • **1、使用了线程不安全的ArrayList作为公共变量
        • **2、每次给Arraylist重新赋值的时候都创建了一个新的对象,堆积了大量要回收的旧对象,导致CPU飙升****
    • 思路&方案
          • 1、在方法之前加 **synchronized** 关键字。
          • 2、使用**ThreadLocal**变量。
    • 总结

背景

存入redis的值,可能会出现错误的情况。如果出现错误,接口将会报错。
多个方法一起修改一个公共变量的值,造成数据混乱,导致存入redis中的key值错误
还有每次登陆都会重现创建一个对象,放到公共变量中,遇到并发,对象会被大量地创建,
上一个对象会失去引用,等待垃圾回收器进行回收,导致CPU飙升。

在这里插入图片描述
上边公共变量的字符串拼接出现问题,导致下边这张图中的域名中的字符串出现问题。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由上图可知:

**1、使用了线程不安全的ArrayList作为公共变量

2、每次给Arraylist重新赋值的时候都创建了一个新的对象,堆积了大量要回收的旧对象,导致CPU飙升**

(GC会消耗大量CPU和内存来实现垃圾回收)

思路&方案

复现问题:

测试类:

public class ThreadTest {//新建一个list作为成员变量List 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() {@Overridepublic 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> 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方法将对象进行清除。
现状:在这里插入图片描述
在这里插入图片描述

这样就不会持续开辟内存空间。

总结

考虑成本,凡事都要考虑成本。
我们要有无限思维,当只有一个对象的时候我们写的代码不会出现上述问题,但是对象一多就会出现数据错乱的问题,内存飙升的问题,我们的系统不会只有一个用户,所以无限思维是我们必须要考虑的一件事情,考虑并发,考虑将来。而不是只顾眼前。

相关内容

热门资讯

应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
cad打印线条粗细设置 cad... 004-线型(下)打印样式设置和线型文件使用一、线宽设置方法制图规范里边的线宽要求,我们已经定义好,...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
荼蘼什么意思 岁月缱绻葳蕤生香... 感谢作者【辰夕】的原创独家授权分享编辑整理:【多肉植物百科】百科君坐标:云南 曲靖春而至,季节流转,...