1. 概述

在操作系统中,我们经常需要处理多个任务的执行问题。这时候就离不开两个关键技术:并发(Concurrency)并行(Parallelism)

虽然这两个术语听起来很像,但它们的实现机制和适用场景完全不同。这篇文章会从底层原理到实际应用,带你彻底搞懂并发与并行的区别与联系。


2. 核心定义

在深入探讨并发与并行之前,先明确几个关键概念:

  • 多处理(Multiprocessing):在一个计算机系统中使用多个CPU。
  • 多线程(Multithreading):一个进程可以包含多个线程,这些线程可以并发执行。
  • 分布式计算(Distributed Computing):多个计算机系统作为一个整体运行,可以通过局域网或广域网连接。
  • 多核处理器(Multicore Processor):一个芯片上集成多个核心处理单元。
  • 流水线(Pipelining):多个指令在执行时可以重叠执行。

这些概念是理解并发和并行的基础,务必掌握。


3. 并发(Concurrency)

并发是指多个任务在重叠的时间段内执行。任务之间可以交替执行,但不一定真正同时运行

比如,你一边听歌一边打字,看起来是同时进行的,其实操作系统是在多个任务之间快速切换,给人“同时进行”的错觉。

3.1 并发是如何工作的?

并发的核心目标是最大化CPU利用率。当一个线程在等待IO、数据库操作或外部程序时,另一个线程可以继续使用CPU。

操作系统通过时间片轮转(Round Robin)和上下文切换来实现并发。如下图所示:

concurrency-example

⚠️ 注意:并发执行时,多个线程共享资源,尤其是写操作时容易引发数据竞争(Race Condition),必须通过锁机制(如synchronized、ReentrantLock)来保证线程安全。


4. 并行(Parallelism)

并行是指多个任务在同一时刻真正同时执行。它依赖于多核处理器或分布式系统。

比如,一个多核CPU可以真正同时执行多个线程,或者一个Hadoop集群可以同时处理多个节点上的数据。

4.1 并行是如何工作的?

并行通常出现在以下几种场景:

  • ✅ 多核CPU上的多线程任务
  • ✅ 分布式系统中的多个节点协同处理
  • ✅ 流水线式指令执行(如GPU计算)

如下图所示,多个任务在不同核心上并行执行:

parallelism-example

并行的优势在于提升计算效率,适用于计算密集型任务,如图像处理、大数据分析等。


5. 并发 vs 并行:关键区别

对比项 并发(Concurrency) 并行(Parallelism)
执行方式 交替执行,任务切换 真正同时执行
资源要求 单核或多核均可 通常需要多核或分布式系统
适用场景 IO密集型任务(如Web服务器) CPU密集型任务(如图像处理)
实现难度 中等,需处理线程安全 较高,需处理数据同步与分布
典型例子 Java线程池、Netty异步IO Hadoop、Spark、GPU并行计算

5.1 举个例子

下图展示了并发和并行在两个核心上的执行方式:

concurrency-vs-parallelism

左边是并发:两个核心交替执行两个任务;
右边是并行:两个核心同时执行两个任务。

5.2 常见陷阱

并发和并行虽然强大,但如果不小心使用,可能会带来严重问题:

  • 死锁(Deadlock):多个线程互相等待对方释放资源,导致程序卡死。
  • 竞态条件(Race Condition):多个线程同时修改共享变量,导致数据不一致。
  • 资源饥饿(Starvation):某些线程始终得不到CPU时间。
  • 内存泄漏(Memory Leak):未正确释放线程或对象引用,导致内存占用过高。

⚠️ 踩坑提醒:在并发编程中,不要盲目使用Thread.sleep()来解决同步问题,这是“掩耳盗铃”的做法,真正应该用的是锁、原子操作或并发工具类。


6. 支持并发与并行的编程语言和框架

Java 作为一门成熟的并发编程语言,内置了丰富的并发工具类(如java.util.concurrent包),同时也支持并行计算(如Fork/Join框架)。

下面是一些支持并发与并行的主流语言和框架:

✅ 共享内存语言

  • Java(推荐)
  • C(配合POSIX线程库)
  • C++

✅ 分布式内存语言

  • Go(推荐用于并发和分布式)
  • Rust(推荐用于系统级并发)
  • MPI(C/C++)

✅ 并行函数式语言

  • Scala(Akka框架)
  • LISP(早期并行语言)

✅ 大数据处理框架

  • Hadoop
  • Spark(推荐)

✅ 并发工具库

  • Java的ExecutorServiceForkJoinPool
  • Go的goroutinechannel
  • Python的multiprocessingasyncio

✅ 建议:掌握并发/并行编程,不要只看语言本身,更重要的是理解底层机制,比如线程调度、锁机制、内存模型等。


7. 总结

并发和并行是现代系统设计中不可或缺的两个概念:

  • 并发:多个任务交替执行,提升响应性,适用于IO密集型任务。
  • 并行:多个任务同时执行,提升吞吐量,适用于CPU密集型任务。
  • ⚠️ 并发 ≠ 并行,它们是两个不同的概念,但可以结合使用。
  • 并发编程容易出错,要特别注意线程安全、死锁、竞态等问题。
  • Java程序员应该熟练掌握并发编程,了解线程池、锁机制、volatile关键字、CAS算法等核心知识点。

掌握了并发与并行,才能写出高性能、高可用的系统。否则,再多的CPU资源也发挥不出来。


原始标题:Concurrency vs Parallelism