【高并发】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 密集、可拆分任务 。

✅ 合理选择 ForkJoinPool 或 parallelStream() 提升效率!

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

相关推荐
xcl092528 分钟前
北京24小时自助健身房系统软件开发实战:从架构到部署全流程指南
java·spring boot·架构
一 乐2 小时前
动漫书销售商城|基于springboot + vue动漫书销售商城(源码+数据库+文档)
java·数据库·vue.js·spring boot·毕业设计
卓怡学长2 小时前
w214基于jsp知道特产网
java·intellij-idea
步行cgn3 小时前
Spring 注解使用详解
java·spring
一条小小yu3 小时前
Spring IoC的理解
java·后端·spring
落魄实习生3 小时前
Agent Scope Java 2.x 系列【7】工具使用
java·开发语言·ai
旺仔学长 哈哈3 小时前
springboot钓鱼爱好者交流平台APP设计与实现
java·spring boot·mysql·充电桩管理系统
自强的小白5 小时前
核心功能(Service接口)
java·mybatis
乌暮6 小时前
深入理解 Java 泛型:把「万能盒子」用对、用稳
java·开发语言·后端·学习