基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

线程间通信机制

知识点图片

本文总结了线程通信的五种核心方式:共享内存、等待通知、管道流、JUC工具类及Future异步结果。

线程间的通信(Thread Communication)是指在多线程环境中,线程之间如何交换信息、协调动作以及共享数据。

由于线程共享进程的内存空间(主要是堆内存),它们天然就可以通过读写共享变量来“通信”。但是,为了保证数据的安全性和逻辑的正确性(例如:A线程必须在B线程完成某事后才能继续执行),我们需要特定的机制来控制这种通信。

以下是几种主要的线程间通信方式(以 Java 语言为例,但概念通用于大多数编程语言):


1. 基于共享内存(Shared Memory)

这是最基础的通信方式,线程直接读写同一块内存区域。

  • volatile 关键字(保证可见性):

    • 原理: 当一个变量被声明为 volatile,任何线程对它的修改都会立即刷新到主内存中,其他线程读取时会强制从主内存读取。
    • 场景: 作为一个简单的信号标记(flag)。例如,线程 A 修改 stop = true,线程 B 检测到后停止运行。
    • 局限: 只能保证可见性,不能保证原子性(不适合计数器等场景)。
  • 共享对象/变量 + 锁(synchronized / Lock):

    • 原理: 通过锁机制,确保同一时刻只有一个线程能修改共享变量。
    • 场景: 多个线程同时修改银行账户余额。

2. 等待/通知机制(Wait/Notify)

这是经典的线程协作方式,用于解决“线程 A 需要等待线程 B 完成某项工作”的问题。

  • Object 类的 wait()notify() / notifyAll()

    • 必须在 synchronized 同步代码块中使用。
    • wait(): 当前线程释放锁,进入等待状态,直到被唤醒。
    • notify(): 随机唤醒一个在该对象上等待的线程。
    • 示例(生产者-消费者模型): 队列满了,生产者 wait;消费者取走数据后,notify 生产者。
  • Condition 接口(配合 ReentrantLock):

    • synchronized 更灵活。可以创建多个 Condition(例如 notFullnotEmpty)。
    • 使用 await() 替代 wait()signal() 替代 notify()
    • 优势: 可以实现精准唤醒某类等待的线程。

3. 管道流(Piped Stream)

这是一种基于数据流的通信方式,模仿了操作系统中的管道概念。

  • 类: PipedInputStream / PipedOutputStream (字节流) 或 PipedReader / PipedWriter (字符流)。
  • 原理: 一个线程写入管道,另一个线程从管道读取。数据在内存中传输,不经过文件系统。
  • 场景: 线程间传输大量数据,且不需要共享变量。

4. 并发工具类(JUC - java.util.concurrent)

Java 在 JDK 1.5 后引入了高级并发包,提供了更高级、更易用的通信方式:

  • BlockingQueue(阻塞队列):

    • 最推荐的方式。它是线程安全的队列。
    • 原理: 当队列满时,放入元素会阻塞;当队列空时,取出元素会阻塞。
    • 场景: 解耦生产者和消费者,无需手动写 wait/notify
  • CountDownLatch(倒计时门闩):

    • 场景: 线程 A 等待其他 N 个线程都执行完任务后,才能继续执行。
    • 用法: 主线程调用 await(),子线程执行完调用 countDown()
  • CyclicBarrier(循环栅栏):

    • 场景: 一组线程互相等待,直到所有线程都到达某个屏障点(Barrier),然后同时继续执行。
    • 例子: 游戏加载,所有人进度条都跑完(到达屏障),游戏才开始。
  • Semaphore(信号量):

    • 场景: 控制同时访问特定资源的线程数量。
    • 用法: 类似于拿许可证,处理完后归还。

5. Future 和 CompletableFuture

用于获取线程的执行结果。

  • Callable + Future

    • 传统的 Runnable 没有返回值。Callable 可以返回结果。
    • 主线程提交任务后,可以通过 future.get() 阻塞等待子线程计算完成并获取结果。
  • CompletableFuture (Java 8+):

    • 支持异步回调。当线程 A 计算完成后,自动触发线程 B 执行后续操作,实现了流式的线程通信。

总结与对比

通信方式 核心机制 适用场景 复杂度
volatile 共享内存可见性 简单的状态标记(开关)
wait/notify 锁 + 信号 精细控制线程暂停/恢复 高 (易出错)
BlockingQueue 内部锁 + 队列 生产者-消费者模型 (最常用) 低 (封装好)
CountDownLatch 计数器 一等多 (主线程等子线程)
CyclicBarrier 计数器 多等多 (所有线程同起跑线)
Pipe 输入输出流 传输数据流
Future 返回值句柄 需要获取子线程执行结果

最佳实践建议:
在实际开发中,尽量避免使用底层的 wait/notify,因为容易造成死锁或逻辑错误。应优先使用 BlockingQueue 进行数据传递,使用 CompletableFuture 进行异步编排,或使用 CountDownLatch 进行流程控制。

00:00
00:00