线程通信是指同一个进程内的多个线程,相互传递数据、协调执行顺序的机制。

因为多线程共享进程的内存空间,通信比进程间通信简单,但也需要解决线程安全、同步、数据传递三大问题。

一、核心本质

多个线程协作,共享数据、交替执行、传递消息。

  • 为什么需要线程通信?

    • 线程 A 计算完结果,需要交给线程 B 使用
    • 控制执行顺序:线程 B 必须等线程 A 执行完再运行
    • 多个线程操作共享数据,防止冲突(线程安全)
  • 线程通信的本质

    • 共享变量 + 同步机制
    • 等待 / 唤醒机制
    • 管道 / 队列传输

二、5 种常用通信方式

1. 共享变量(volatile)

  • 作用:用于状态标记,保证变量可见性。
  • 原理:可见性,线程读到最新主内存数据
  • 用法:volatile boolean flag 启停线程
  • 缺点:无法精准控制执行顺序

2. wait /notify/notifyAll(Object 方法)

  • 必须在synchronized 锁内使用,用于等待 - 唤醒
  • wait:释放锁,进入等待
  • notify:随机唤醒一个等待线程
  • notifyAll:唤醒所有等待线程
  • 场景:生产者消费者

3. Lock + Condition(JDK1.5 以后)

  • 替代 wait/notify,比 synchronized 更灵活,精准唤醒指定线程
  • 可创建多个条件队列,分工等待唤醒
Lock lock = new ReentrantLock();
Condition c1 = lock.newCondition();
Condition c2 = lock.newCondition();

4. 阻塞队列 BlockingQueue(最常用)

自动实现等待、唤醒、线程安全,不用写 wait/notify。

BlockingQueue<String> queue = new ArrayBlockingQueue<>(1);

// 生产者
queue.put("数据");

// 消费者
String data = queue.take();
  • put():满了就阻塞
  • take():空了就阻塞

✅ 开发首选,简单、安全、不易出错。

5. 管道流 PipedInputStream / PipedOutputStream

  • 线程间直接字节数据传递
  • 多用于字节消息传输

6. 工具类通信

  • CountDownLatch(闭锁):等待所有线程做完再执行
  • CyclicBarrier(栅栏):线程集齐再一起出发
  • Semaphore(信号量):控制并发线程数

三、Java 多线程并发工具类

闭锁(CountDownLatch)与 栅栏(CyclicBarrier)是Java 多线程并发工具类,专门用来控制线程执行顺序、协调多线程同步。

1. CountDownLatch(门栓、倒计时锁)

核心一句话等所有线程都干完,主线程再继续执行。像倒计时,倒计时结束,门才打开。

核心特点

  • 一次性使用:计数到 0 就结束,不能重置
  • 等待方是主线程:主线程等其他线程
  • 作用:等待一批线程执行完成

常用方法:

  • new CountDownLatch(int count):初始化计数器
  • countDown():计数器 -1
  • await():阻塞等待,直到计数器 = 0

经典场景:

  • 主线程等 5 个初始化线程全部完成,再开始运行
  • 游戏加载:等所有资源加载完,才进入游戏
// 主线程等 3 个线程执行完
CountDownLatch latch = new CountDownLatch(3);

// 线程执行完,计数器-1
new Thread(() -> {
    latch.countDown();
}).start();

// 主线程阻塞等待
latch.await(); 

2. CyclicBarrier(循环屏障)

核心一句话一组线程互相等待,全部到齐后,再一起同时执行。聚会,所有人到齐了,才开饭

核心特点:

  • 可循环使用:执行完一轮,可以继续用
  • 线程之间互相等待
  • 作用:一组线程同步开始执行

常用方法:

  • new CyclicBarrier(int parties):等待的线程数
  • await():我到了,等其他人

经典场景:

  • 多线程同时开始执行压测
  • 所有线程准备好,同时开始执行任务
// 3 个线程互相等待
CyclicBarrier barrier = new CyclicBarrier(3);

new Thread(() -> {
    // 等待其他线程
    barrier.await(); 
    // 所有线程到齐后,同时执行这里
}).start();

3. Semaphore(信号量)

Semaphore = 许可证管理器 → 控制同时能运行的线程数量!

核心原理:

  • ① 初始化设置许可证数量
  • ② 线程要执行,必须先获取许可证
  • ③ 用完必须归还许可证
  • ④ 没许可证 → 线程阻塞等待

常用方法:

// 1. 创建:指定许可证数量
Semaphore semaphore = new Semaphore(3);

// 2. 获取许可证(获取不到就阻塞)
semaphore.acquire();

// 3. 归还许可证
semaphore.release();

常用场景:

  • 接口限流(最多 N 个请求同时访问)
  • 池化资源控制(数据库连接池、线程池)
  • 共享资源限流(文件读写、打印机)

四、一句话区分

  • 共享变量:看信号
  • wait/notify:阻塞唤醒
  • 实际开发优先用阻塞队列,最简单安全
  • 阻塞队列:安全传数据
  • 闭锁 栅栏:批量等待协作
  • 工作中:等待完成用闭锁,同步开始用栅栏
  • CountDownLatch:倒计时,主线程等待,不可重用
  • CyclicBarrier:循环屏障,线程互相等待,可重用
  • Semaphore 用来限流
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐