并发 vs 并行编程详解
理解并发(Concurrency)和并行(Parallelism)是掌握多线程编程的核心基础。下面通过生活化比喻、技术原理和实际代码示例,帮助你彻底区分这两大概念。
一、核心概念对比
1. 生活化比喻
概念 | 比喻场景 | 核心区别 |
---|
并发 | 餐厅单服务员多桌点餐 | 交替处理(看似同时,实际快速切换) |
并行 | 餐厅多服务员同时服务不同桌 | 真正同时执行(物理上的同步处理) |
2. 技术定义
- 并发:多个任务在同一时间段内交替执行(单核或多核均可)
- 并行:多个任务真正同时执行(必须多核支持)
二、核心原理图解
1. 并发(单核CPU)
- 特点:通过时间片轮转(Time Slicing)模拟"同时"执行
- 场景:Web服务器处理多请求、GUI界面响应
2. 并行(多核CPU)
三、Java中的实现方式
1. 并发编程示例
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("处理订单");}
});
executor.submit(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("烹饪菜品");}
});
executor.shutdown();
2. 并行编程示例
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream().forEach(n -> process(n));
numbers.parallelStream().forEach(n -> process(n));
四、选择依据与优化策略
1. 何时选择并发?
- 任务需要频繁等待I/O(如网络请求、文件读写)
- 需要保持用户界面响应
- 任务间存在依赖关系
2. 何时选择并行?
- 计算密集型任务(如视频编码、矩阵运算)
- 数据可分片处理且无共享状态
- 硬件支持多核(如服务器集群)
3. 性能优化要点
场景 | 优化策略 |
---|
高并发I/O | 使用NIO(非阻塞I/O) |
计算密集型并行 | 使用Fork/Join框架 |
数据共享 | 减少锁竞争(CAS原子操作) |
五、常见误区与问题
1. 误区:并发一定比顺序执行快
- 真相:如果任务都是CPU密集型,单核上的并发反而更慢(切换开销)
2. 误区:并行可以无限加速
3. 典型问题:竞态条件(Race Condition)
public class Counter {private int count = 0;public void increment() {count++; }
}
private AtomicInteger count = new AtomicInteger(0);
public void increment() {count.incrementAndGet();
}
六、总结与记忆口诀
对比总结表
维度 | 并发(Concurrency) | 并行(Parallelism) |
---|
目标 | 提高资源利用率 | 提高计算速度 |
实现条件 | 单核/多核均可 | 必须多核/分布式 |
典型应用 | Web服务器、GUI应用 | 大数据处理、科学计算 |
编程重点 | 任务调度、状态同步 | 任务拆分、负载均衡 |
记忆口诀
“并发像单核餐厅,服务员快速轮转桌,
并行是多核厨房,厨师同时炒菜不耽搁。
选并发还是并行?看任务是等I/O或计算,
共享资源要小心,锁和原子操作别忘做!”