parallelStream线程问题及解决方案

parallelStream可以在多个线程中并行处理流数据,提高性能。然而,如果在处理过程中涉及共享的可变状态,可能会导致线程不安全的问题。以下是一个简单的示例演示了如何在不正确的使用情况下导致线程安全问题:

复制代码
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class ParallelStreamDemo {

    public static void main(String[] args) {
        // 使用一个普通的ArrayList来存储结果
        List<Integer> resultList = new ArrayList<>();

        // 创建一个范围从1到1000的列表
        List<Integer> numbers = new ArrayList<>();
        for (int i = 1; i <= 1000; i++) {
            numbers.add(i);
        }

        // 使用parallelStream尝试将每个数字的平方加入resultList
        numbers.parallelStream().forEach(number -> {
            // 这是一个临界区,resultList被多个线程同时修改
            resultList.add(number * number);
        });

        // 输出结果大小
        System.out.println("Expected size: " + numbers.size());
        System.out.println("Actual size: " + resultList.size());

        // 打印结果列表中的一些内容
        System.out.println("Some elements in the result: " + resultList.subList(0, 10));
    }
}

问题分析:

  1. 线程不安全ArrayList是线程不安全的。在多个线程同时进行写操作时,可能导致数据丢失或者其他不一致的问题。

  2. 结果不准确 :实际输出的resultList可能小于预期,因为当多个线程同时尝试写入同一个内存位置时,它们可能不会正确处理并发访问,导致某些写操作被忽略。

解决方案:

若要解决这样的问题,可以选择一些线程安全的集合类,例如 CopyOnWriteArrayList 或者使用同步机制来确保线程安全

复制代码
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class ParallelStreamThreadSafeDemo {

    public static void main(String[] args) {
        // 使用线程安全的CopyOnWriteArrayList来存储结果
        List<Integer> resultList = new CopyOnWriteArrayList<>();

        // 创建一个范围从1到1000的列表
        List<Integer> numbers = new ArrayList<>();
        for (int i = 1; i <= 1000; i++) {
            numbers.add(i);
        }

        // 使用parallelStream添加数字的平方到resultList
        numbers.parallelStream().forEach(number -> {
            resultList.add(number * number);
        });

        // 输出结果大小
        System.out.println("Expected size: " + numbers.size());
        System.out.println("Actual size: " + resultList.size());
        System.out.println("Some elements in the result: " + resultList.subList(0, 10));
    }
}

通过使用CopyOnWriteArrayList,我们确保了在并发写时是线程安全的,这样就可以得到预期的结果。

相关推荐
腻害兔2 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社3 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
萧瑟余晖4 小时前
JDK 26 新特性详解
java·开发语言
马优晨4 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
维天说7 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
Zane19948 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端
噢,我明白了9 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
吠品9 小时前
Zabbix Web界面误报Server未运行的排查与解决
java·服务器·数据库
啊湘9 小时前
天气查询API接口 按月Token鉴权 实时天气 物联网可用 文档齐全
java·后端·struts
Java内核笔记9 小时前
告别十亿美元的错误 : Spring Boot 4 空安全 (JSpecify) 实战
java·spring boot·后端