【高并发】Java 并行与串行深入解析:性能优化与实战指南

Java 并行与串行深入解析:性能优化与实战指南

在高性能应用开发中,我们常常会面临 串行(Serial)并行(Parallel) 的选择。串行执行任务简单直观,但并行能更高效地利用 CPU 资源,提高吞吐量。然而,并行并不总是比串行快,如何合理选择和优化并行任务,才是性能提升的关键。本文将深入解析 Java 并行与串行的原理 ,并结合 实战代码 带你掌握 高效的并行计算 方法。


1. 什么是串行与并行?

(1)串行(Serial)

串行指的是任务按顺序执行 ,一个任务执行完后,才会执行下一个任务。例如,以下代码模拟 读取数据库 → 计算数据 → 写入文件 的串行执行流程:

java 复制代码
public class SerialProcessing {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        readFromDatabase();  // 假设耗时 2s
        processData();       // 假设耗时 3s
        writeToFile();       // 假设耗时 2s
        System.out.println("总耗时: " + (System.currentTimeMillis() - start) + " ms");
    }

    static void readFromDatabase() { sleep(2000, "读取数据库"); }
    static void processData() { sleep(3000, "计算数据"); }
    static void writeToFile() { sleep(2000, "写入文件"); }

    static void sleep(int millis, String task) {
        try { 
            System.out.println(task + " 开始...");
            Thread.sleep(millis); 
            System.out.println(task + " 结束");
        } catch (InterruptedException e) {}
    }
}

执行结果

读取数据库 开始...
读取数据库 结束
计算数据 开始...
计算数据 结束
写入文件 开始...
写入文件 结束
总耗时: 7000 ms

🚨 问题 :任务串行执行 ,总耗时 = 2s + 3s + 2s = 7s,如果任务更多,系统响应会非常慢。


(2)并行(Parallel)

并行执行任务意味着 多个任务同时运行 ,在多核 CPU 环境下能够显著提高效率。例如,我们可以使用 多线程并行执行任务

java 复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ParallelProcessing {
    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        
        ExecutorService executor = Executors.newFixedThreadPool(3);
        executor.execute(() -> sleep(2000, "读取数据库"));
        executor.execute(() -> sleep(3000, "计算数据"));
        executor.execute(() -> sleep(2000, "写入文件"));

        executor.shutdown();
        while (!executor.isTerminated()) { Thread.sleep(100); }

        System.out.println("总耗时: " + (System.currentTimeMillis() - start) + " ms");
    }

    static void sleep(int millis, String task) {
        try { 
            System.out.println(task + " 开始...");
            Thread.sleep(millis); 
            System.out.println(task + " 结束");
        } catch (InterruptedException e) {}
    }
}

执行结果(并行执行,可能不同)

读取数据库 开始...
计算数据 开始...
写入文件 开始...
读取数据库 结束
写入文件 结束
计算数据 结束
总耗时: 3000 ms

并行执行,耗时大幅减少!

🚀 比串行执行快了 7s → 3s,大幅优化了执行时间。


2. 并行 vs. 串行:如何选择?

对比项 串行(Serial) 并行(Parallel)
执行方式 任务逐个执行 任务同时执行
CPU 利用率
吞吐量
适用场景 任务依赖强,逻辑顺序不可分 任务独立,计算密集型
资源消耗 低(一个线程) 高(多线程)
调试难度 简单 复杂(需考虑同步、锁)

🚀 适合使用并行的场景

计算密集型任务 (如大数据计算、AI 训练)

I/O 密集型任务 (如多个 API 调用、批量文件处理)

任务独立,可拆分成多个子任务

🚨 不适合并行的场景

任务之间强依赖 (如步骤 A 结果决定 B 的输入)

线程切换开销大,反而影响性能(如小任务并行导致频繁上下文切换)


3. Java 并行实战

(1)使用 ForkJoinPool 并行计算

ForkJoinPool 是 Java 7 引入的 并行计算框架 ,适用于大规模递归任务,如 并行数组求和

java 复制代码
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;

class ParallelSum extends RecursiveTask<Long> {
    private static final int THRESHOLD = 10000;
    private long[] array;
    private int start, end;

    public ParallelSum(long[] array, int start, int end) {
        this.array = array;
        this.start = start;
        this.end = end;
    }

    protected Long compute() {
        if ((end - start) <= THRESHOLD) { 
            long sum = 0;
            for (int i = start; i < end; i++) sum += array[i];
            return sum;
        } else {
            int mid = (start + end) / 2;
            ParallelSum leftTask = new ParallelSum(array, start, mid);
            ParallelSum rightTask = new ParallelSum(array, mid, end);
            leftTask.fork();  // 异步执行左半部分
            return rightTask.compute() + leftTask.join();
        }
    }
}

public class ForkJoinExample {
    public static void main(String[] args) {
        long[] array = new long[1000000];
        for (int i = 0; i < array.length; i++) array[i] = i;

        ForkJoinPool pool = new ForkJoinPool();
        long sum = pool.invoke(new ParallelSum(array, 0, array.length));

        System.out.println("总和: " + sum);
    }
}

适用于大规模数据计算,充分利用 CPU 并行能力!


(2)使用 parallelStream() 并行处理集合

java 复制代码
import java.util.List;
import java.util.stream.IntStream;

public class ParallelStreamExample {
    public static void main(String[] args) {
        List<Integer> numbers = IntStream.rangeClosed(1, 1000000).boxed().toList();

        long start = System.currentTimeMillis();
        int sum = numbers.parallelStream().mapToInt(Integer::intValue).sum();
        System.out.println("总和: " + sum + ", 耗时: " + (System.currentTimeMillis() - start) + " ms");
    }
}

比传统 for 循环更快!


4. 总结

串行适用于任务依赖强、执行顺序严格的场景

并行适用于 CPU 密集、I/O 密集、可拆分任务

合理选择 ForkJoinPoolparallelStream() 提升效率!

并行计算是高性能开发的关键,希望本文能帮助你更高效地编写 Java 并行程序!🚀🚀🚀

相关推荐
~Yogi9 分钟前
每日学习Java之一万个为什么?(Maven篇+RPC起步+CICD起步)(待完善)
java·学习·maven
银之夏雪22 分钟前
ESLint 深度解析:原理、规则与插件开发实践
java·前端·javascript
重生之成了二本看我逆天改命走向巅峰35 分钟前
从0搭建Tomcat第二天:深入理解Servlet容器与反射机制
java·开发语言·笔记·学习·servlet·tomcat·idea
rkmhr_sef37 分钟前
Java进阶:Dubbo
java·开发语言·dubbo
不止会JS42 分钟前
cursor使用经验分享(java后端服务开发向)
java·开发语言·经验分享·cursor
码熔burning1 小时前
(二 十 三)趣学设计模式 之 解释器模式!
java·设计模式·解释器模式
三水气象台1 小时前
对ArrayList中存储的TreeNode的排序回顾
java·数据结构·算法·huffman tree
牛马baby2 小时前
Java高频面试之集合-03
java·开发语言·面试
用手手打人2 小时前
多线程&JUC(二)
java·开发语言
剑走偏锋o.O2 小时前
Jedis学习笔记
java·redis·笔记·学习·jedis