案例15-ArrayList线程不安全,共用全局变量导致数据错乱问题,占用内存情况

这篇具有很好参考价值的文章主要介绍了案例15-ArrayList线程不安全,共用全局变量导致数据错乱问题,占用内存情况。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

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

arraylist内存占用较多,java,jvm,算法
上边公共变量的字符串拼接出现问题,导致下边这张图中的域名中的字符串出现问题。

arraylist内存占用较多,java,jvm,算法
arraylist内存占用较多,java,jvm,算法
arraylist内存占用较多,java,jvm,算法
由上图可知:

**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+]

实际上:
arraylist内存占用较多,java,jvm,算法

注重变量的作用域和生命周期,还要考虑并发量高的时候考虑线程安全,并发的时候还要将对象进行置空。

第一个问题解决方案:

1、在方法之前加 synchronized 关键字。

arraylist内存占用较多,java,jvm,算法

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());
    }
}

结果:
arraylist内存占用较多,java,jvm,算法

第二个问题(对象重复创建导致CPU和内存飙升)解决方案:
1、使用List的RemoveAll方法将对象进行清除。
现状:arraylist内存占用较多,java,jvm,算法
arraylist内存占用较多,java,jvm,算法

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

总结

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

并发如何解决?

并发问题是在多线程或多进程环境中经常出现的挑战,可能导致数据不一致、死锁等问题。解决并发问题需要考虑各种技术和策略,下面是一些常见的方法:

锁机制: 使用锁是解决并发问题的一种常见方法。通过在关键代码段周围加锁,只允许一个线程或进程访问临界资源,从而防止多个线程同时修改相同数据。然而,锁可能导致死锁和性能问题,因此需要小心设计和管理。

同步机制: 同步方法如synchronized块或方法可以确保在同一时间只有一个线程可以访问共享资源。这有助于避免数据竞争和不一致问题。

并发容器: Java提供了许多并发容器,如ConcurrentHashMap、ConcurrentLinkedQueue等,这些容器在多线程环境中提供了更好的性能和线程安全性。

原子操作: 原子操作是不可分割的操作,可以确保多线程环境中的数据一致性。Java提供了一些原子类,如AtomicInteger、AtomicReference等,用于执行原子操作。

线程池: 使用线程池可以有效地管理并发任务。线程池可以控制线程的数量,从而减少线程创建和销毁的开销,提高性能和资源利用率。

避免共享状态: 尽量避免共享状态,通过将状态封装在对象中,每个线程操作自己的对象实例,从而避免竞争和并发问题。

使用不可变对象: 不可变对象在多线程环境中是线程安全的,因为它们不会改变。使用不可变对象可以避免并发问题。

内存模型和可见性: 了解Java内存模型和可见性原则,确保一个线程对共享变量的修改对其他线程可见。

死锁避免和解决: 死锁是一种并发问题,当多个线程互相等待对方释放资源时发生。避免死锁可以通过破坏四个必要条件之一来实现:互斥、持有并等待、不可抢占、循环等待。

并发工具: Java提供了许多并发工具,如CountDownLatch、CyclicBarrier、Semaphore等,用于协调多个线程的执行和等待。

总之,解决并发问题需要综合考虑设计、同步、数据管理和线程控制等方面。选择适当的策略和技术取决于问题的复杂性和性能要求。同时,良好的并发编程实践也需要深入了解多线程和并发编程的原则。文章来源地址https://www.toymoban.com/news/detail-783528.html

到了这里,关于案例15-ArrayList线程不安全,共用全局变量导致数据错乱问题,占用内存情况的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Jmeter(二十七):BeanShell PostProcessor跨线程全局变量使用

    在性能测试中,两个相关联的接口不一定都在同一个线程组,遇见这种情况时,我们要进行跨线程组传参,此处用登录和查询配送单两个请求举例; 1、登录请求中配置json提取器,将接口返回的token保存在变量中;  2、登录请求中配置BeanShell 后置处理程序,将token保存到全局

    2024年02月11日
    浏览(30)
  • C++多线程场景中的变量提前释放导致栈内存异常

    在子线程中尝试使用当前函数的资源 ,是非常危险的,但是C++支持这么做。因此C++这么做可能会造成栈内存异常。 上述是一个正常的多线程代码。 但是如果将其中多线程传参设置为引用传递,可能就会造成栈内存异常了,如下所示: 编译成功,但是运行失败。 运行结果:

    2024年02月13日
    浏览(45)
  • 单线程、同步、异步、预解析、作用域、隐式全局变量、对象创建、new

    cpu 资源分配的最小单位 一个进程可以有多个线程 cpu 调度的最小单位 线程建立在进程的建立基础上的一次程序的运行单位 线程分为:单线程 多线程 单线程:js是单线程 (同一个时间只能完成一个任务) 多线程:百度是多线程 同步任务是指在主线程上排队的任务,只有当前

    2024年01月22日
    浏览(31)
  • 面试官问 : ArrayList 不是线程安全的,为什么 ?(看完这篇,以后反问面试官)

    金三银四 ? 也许,但是。 近日,又收到金三银四一线作战小队成员反馈的战况 : 我不管你从哪里看的面经,但是我不允许你看到我这篇文章之后,还不清楚这个面试问题。 本篇内容预告:   ArrayList 是线程不安全的, 为什么 ? ① 结合代码去探一探所谓的不安全  ② 我们

    2024年02月02日
    浏览(47)
  • JavaEE 初阶篇-线程安全的集合类、多线程环境使用 ArrayList、队列、哈希表(HashMap 、ConCurrentHashMap 、HashTable 的区别)

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍   文章目录         1.0 线程安全的集合类         1.2 线程安全的集合类 - Vector         1.3 线程安全的集合类 - Stack         1.4 线程安全的集合类 - HashTable         2.0 多线程环境使用 ArrayList        

    2024年04月25日
    浏览(39)
  • jmeter如何将提取到的token值设置为全局变量使其可以跨线程组使用

    我们用到jmeter去进行接口测试时,经常会遇到要跨线程组使用变量的场景,下面用json提取器提取token值并设置为全局变量的方法做为示范: 需要用到的是: 线程组---http请求---json提取器----Beanshell取样器 ;其他元件大家根据自己需要去配置即可,json提取器和正则表达式提取器

    2024年02月16日
    浏览(37)
  • Java【多线程基础3】导致线程不安全的 4 种原因及解决方式

    📕各位读者好, 我是小陈, 这是我的个人主页 📗小陈还在持续努力学习编程, 努力通过博客输出所学知识 📘如果本篇对你有帮助, 烦请点赞关注支持一波, 感激不尽 📙 希望我的专栏能够帮助到你: JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统

    2024年02月02日
    浏览(38)
  • 【Java并发编程】变量的线程安全分析

    1.成员变量和静态变量是否线程安全? 如果他们没有共享,则线程安全 如果被共享: 只有读操作,则线程安全 有写操作,则这段代码是临界区,需要考虑线程安全 2.局部变量是否线程安全 局部变量是线程安全的 当局部变量引用的对象则未必 如果给i对象没有逃离方法的作用

    2024年02月08日
    浏览(41)
  • 【探索Linux】—— 强大的命令行工具 P.21(多线程 | 线程同步 | 条件变量 | 线程安全)

    在上一篇文章中,我们详细探讨了多线程编程的基础概念,包括线程互斥、互斥锁以及死锁和资源饥饿等问题。我们了解到,在多线程环境下,为了防止数据竞争和保证程序的正确性,需要采用一定的同步机制来协调线程之间的执行顺序。本篇文章将继续深入探讨多线程编程

    2024年02月05日
    浏览(35)
  • new ArrayList 不当导致 CPU 飙升。。

    来源:juejin.cn/post/7139202066362138654 昨天线上容器突然cpu飙升,也是第一次排查这种问题所以记录一下~ 首先问题是这样的,周五正在写文档,突然收到了线上报警,发现cpu占用达到了90多,上平台监控系统查看容器,在jvm监控中发现有一个pod在两个小时内产生了61次youngGc一次

    2024年02月13日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包