ArrayList非线程安全记录

2023-11-04

一、问题描述

线上一个查询服务,偶尔会报一次查询出来的结果集合包含null。

二、问题排查

在多线程查询过程中,使用了ArrayList,多线程查询出来后执行ArrayList.add()。然而ArrayList并不是线程安全的集合,会导致null值出现。可以考虑使用SynchronizedList。
在这里插入图片描述
在这里插入图片描述

三、问题复现

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class TestSync {

    private static final Integer n = 100;

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        arrayList();
        System.out.println("arrayList时间:" + (System.currentTimeMillis() - startTime));

        startTime = System.currentTimeMillis();
        synchronizedList();
        System.out.println("synchronizedList时间:" + (System.currentTimeMillis() - startTime));

        startTime = System.currentTimeMillis();
        copyArrayList();
        System.out.println("copyArrayList时间:" + (System.currentTimeMillis() - startTime));

        startTime = System.currentTimeMillis();
        futureList();
        System.out.println("futureList时间:" + (System.currentTimeMillis() - startTime));
    }

    private static void arrayList() {
        List<Integer> testList = new ArrayList<>();
        CountDownLatch countDownLatch = new CountDownLatch(n);
        for (int i=0; i<n; i++) {
            new Thread(() -> {
                testList.add(1);
                countDownLatch.countDown();
            }).start();
        }
        try {
            countDownLatch.await(10, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(testList);
    }

    private static void synchronizedList() {
        List<Integer> testList = Collections.synchronizedList(new ArrayList<>());
        CountDownLatch countDownLatch = new CountDownLatch(n);
        for (int i=0; i<n; i++) {
            new Thread(() -> {
                testList.add(1);
                countDownLatch.countDown();
            }).start();
        }
        try {
            countDownLatch.await(10, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(testList);
    }

    private static void copyArrayList() {
        CopyOnWriteArrayList<Integer> testList = new CopyOnWriteArrayList<>();
        CountDownLatch countDownLatch = new CountDownLatch(n);
        for (int i=0; i<n; i++) {
            new Thread(() -> {
                testList.add(1);
                countDownLatch.countDown();
            }).start();
        }
        try {
            countDownLatch.await(10, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(testList);
    }

    private static void futureList() {
        List<CompletableFuture<Integer>> futureList = new ArrayList<>();
        for (int i=0; i<n; i++) {
            CompletableFuture<Integer> task = CompletableFuture.supplyAsync(() -> 1);
            futureList.add(task);
        }
        CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).join();
        List<Integer> testList = new ArrayList<>();
        futureList.forEach(data -> data.whenComplete((integer, throwable) -> {
            if (Objects.nonNull(throwable)) {
                return;
            }
            testList.add(integer);
        }));
        System.out.println(testList);
    }
}

执行结果:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ArrayList非线程安全记录 的相关文章

  • Java 中的 <-- 是什么? [复制]

    这个问题在这里已经有答案了 我遇到了下面的片段 它输出到4 3 2 1 我从来没有遇到过 lt 在爪哇 Is lt 使 var1 的值变为 var2 的运算符 public class Test public static void mai
  • Java LostFocus 和 InputVerifier,按反向制表符顺序移动

    我有一个 GUI 应用程序 它使用 InputVerifier 在产生焦点之前检查文本字段的内容 这都是很正常的 然而 昨天发现了一个问题 这似乎是一个错误 但我在任何地方都找不到任何提及它的地方 在我将其报告为错误之前 我想我应该问 我在
  • 无法使用 datastax java 驱动程序通过 UDT 密钥从 cassandra 检索

    我正在尝试使用用户定义的类型作为分区键将对象存储在 cassandra 中 我正在使用 datastax java 驱动程序进行对象映射 虽然我能够插入到数据库中 但无法检索该对象 如果我更改分区键以使用非 udt 例如文本 我就能够保存和
  • 我对线程失去了理智

    我想要这个类的对象 public class Chromosome implements Runnable Comparable
  • 自定义列表字段点击事件

    我正在编写一个应用程序 其中我创建了用于显示列表视图的自定义列表字段 我的 CustomListField 包含连续的一个图像和文本 我正在通过单击列表字段行获取字段更改侦听器 但我也想将字段更改侦听器放在图像上 谁能告诉我我该怎么做 这是
  • 如何向我的 Spring MVC REST 服务添加错误?

    如果用户没有输入我正在编码的两个名称 我如何更改 更新来自 Spring MVC 的以下 REST 调用以返回错误 未找到 RequestMapping value name method RequestMethod GET Respons
  • JAXB - 忽略元素

    有什么方法可以忽略 Jaxb 解析中的元素吗 我有一个很大的 XML 文件 如果我可以忽略其中一个大而复杂的元素 那么它的解析速度可能会快很多 如果它根本无法验证元素内容并解析文档的其余部分 即使该元素不正确 那就更好了 例如 这应该只生成
  • ThreeTen 向后移植与 JSR-310 的比较

    由于某些原因 我们现在无法使用 java 8 我们仍然停留在 java 7 上 不过 我想使用新的JSR 310 date time APIs现在 使用官方向后移植 ThreeTen http www threeten org threet
  • 在 Spring 中为 @Pathvariable 添加类级别验证

    在发布这个问题之前 我已经做了很多研究并尝试了很多可用的解决方案 这是我陷入的棘手情况 我有一个 Spring 控制器 它有多个请求映射 它们都有 PathVariables 控制器如下所示 Controller EnableWebMvc
  • 如何更改 Swagger-ui URL 前缀?

    我正在使用 Springfox Swagger2 和 Spring boot 1 5 9 我可以通过此链接访问 swagger UI http localhost 8090 swagger ui html http localhost 80
  • 如何在 IntelliJ IDEA 中运行 akka actor

    来自 Akka 网站文档 然后 这个主要方法将创建所需的基础设施 运行演员 启动给定的主要演员并安排 一旦主要参与者终止 整个应用程序就会关闭 因此 您将能够使用类似于以下的命令运行上面的代码 下列的 java classpath akka
  • Android 认为我没有关闭数据库!为什么?

    我有一个 SQLiteDatabase 数据成员 我在 onCreate 中初始化它 并在 onPause onStop 和 onDestroy 中调用 close 它在 onResume 中重新初始化 它似乎运行得很好 但当我查看调试器时
  • IntelliJ Idea:将简单的 Java servlet(无 JSP)部署到 Tomcat 7

    我尝试按照教程进行操作here http wiki jetbrains net intellij Creating a simple Web application and deploying it to Tomcat部署 servlet
  • 使用 Proguard 通过 Dropbox.com 库混淆 Android 应用程序

    我刚刚创建了一个需要 Dropbox com API 库的 Android 应用程序 我现在尝试在 发布 模式下构建应用程序 并希望在代码上运行混淆器以对其进行混淆 但是 每当我尝试运行 Proguard 时 都会收到以下错误 Progua
  • 类更改(例如字段添加或删除)是否保持 Serialized 的向后兼容性?

    我有一个关于 Java 序列化的问题 在这种情况下 您可能需要修改可序列化类并保持向后兼容性 我有丰富的 C 经验 所以请允许我将 Java 与 NET 进行比较 在我的Java场景中 我需要使用Java的运行时序列化机制序列化一个对象 并
  • Java 8 Stream,获取头部和尾部

    Java 8 引入了Stream http download java net jdk8 docs api java util stream Stream html类似于 Scala 的类Stream http www scala lang
  • Spring Boot 中的 JSTL 支持

    虽然我知道有JSP 支持中的一些限制 http docs spring io spring boot docs current reference html boot features developing web applications
  • Android计算两个日期之间的天数

    我编写了以下代码来查找两个日期之间的天数 startDateValue new Date startDate endDateValue new Date endDate long diff endDateValue getTime star
  • Java 的“&&”与“&”运算符

    我使用的示例来自 Java Herbert Schildt 的完整参考文献 第 12 版 Java 是 14 他给出了以下 2 个示例 如果阻止 第一个是好的 第二个是错误的 因此发表评论 public class PatternMatch
  • 设置 TreeSet 的大小

    有没有办法像数组一样对 Java 集合中的 TreeSet 进行大小限制 例如我们在数组中 anArray new int 10 数组具有固定长度 在创建数组时必须指定该长度 A TreeSet当您向其中添加元素时会自动增长 您无法设置其大

随机推荐