Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

  • Java集合

  • Java并发

    • Java并发概述
    • 线程与进程
    • Thread类与线程生命周期
    • 线程创建与任务模型
    • 线程安全
    • synchronized关键字
    • volatile关键字
    • Java内存模型(JMM)
    • 线程间通信
      • 1. wait/notify 模型
      • 2. WaitSet 与 EntryList
      • 3. 为什么用 while
      • 4. notify 还是 notifyAll
      • 5. 生产者消费者示例
      • 6. Condition
      • 7. park/unpark
      • 8. 更高级通信工具
      • Tips 快问快答
    • 线程池
    • 并发工具类
    • 原子操作类Atomic
    • 并发锁
    • 并发容器
    • ConcurrentHashMap
    • BlockingQueue
    • CopyOnWriteArrayList
    • ThreadLocal
    • Fork/Join框架
    • ScheduledThreadPoolExecutor
    • CompletableFuture
    • 虚拟线程
    • 死锁活锁与线程问题排查
    • 并发编程最佳实践
  • Java IO

  • JVM

  • Java
  • Java并发
Wray
2026-06-24
目录

线程间通信

线程间通信用于让多个线程协调执行顺序和共享状态变化。典型场景是生产者消费者:队列为空时消费者等待,队列满时生产者等待。

# 1. wait/notify 模型

wait、notify、notifyAll 是 Object 的方法,必须在持有对象 monitor 时调用。

synchronized (lock) {
    while (!condition) {
        lock.wait();
    }
    doWork();
}

通知:

synchronized (lock) {
    condition = true;
    lock.notifyAll();
}

# 2. WaitSet 与 EntryList

Monitor
├─ Owner:持锁线程
├─ EntryList:等待获取锁的线程
└─ WaitSet:调用 wait 后等待通知的线程

调用 wait():

线程持有锁
  │
  ▼
调用 wait
  │
  ├─ 释放锁
  └─ 进入 WaitSet

调用 notifyAll():

唤醒 WaitSet 中线程
  │
  ▼
被唤醒线程进入锁竞争
  │
  ▼
重新获得锁后从 wait 返回

被通知不等于立即执行,它还要重新竞争锁。

# 3. 为什么用 while

不推荐:

if (!condition) {
    lock.wait();
}

推荐:

while (!condition) {
    lock.wait();
}

原因:

  • 可能虚假唤醒。
  • 多个线程被唤醒后,条件可能已被其他线程消费。
  • 被唤醒到重新拿锁之间,条件可能变化。

等待条件必须循环检查。

# 4. notify 还是 notifyAll

方法 行为 风险
notify 唤醒一个等待线程 可能唤醒错误类型线程
notifyAll 唤醒所有等待线程 唤醒开销更大

复杂条件下优先 notifyAll,避免信号丢失或唤醒错误线程导致系统卡住。

# 5. 生产者消费者示例

public class SimpleQueue<T> {
    private final Queue<T> queue = new ArrayDeque<>();
    private final int capacity;

    public SimpleQueue(int capacity) {
        this.capacity = capacity;
    }

    public synchronized void put(T item) throws InterruptedException {
        while (queue.size() == capacity) {
            wait();
        }
        queue.offer(item);
        notifyAll();
    }

    public synchronized T take() throws InterruptedException {
        while (queue.isEmpty()) {
            wait();
        }
        T item = queue.poll();
        notifyAll();
        return item;
    }
}

实际开发中优先使用 BlockingQueue,不要重复造队列。

# 6. Condition

Condition 是 Lock 体系中的条件队列。

Lock lock = new ReentrantLock();
Condition notEmpty = lock.newCondition();
Condition notFull = lock.newCondition();

相比一个对象只有一个 WaitSet,Condition 可以有多个等待队列。

ReentrantLock
├─ Condition notEmpty
└─ Condition notFull

这样可以更精准唤醒生产者或消费者。

# 7. park/unpark

LockSupport.park() 和 unpark() 是更底层的阻塞唤醒工具。

LockSupport.park();
LockSupport.unpark(thread);

特点:

  • 不要求先持有 synchronized 锁。
  • unpark 可以先于 park 调用,许可会保留一次。
  • AQS、线程池、并发工具底层大量使用它。

普通业务代码很少直接使用。

# 8. 更高级通信工具

工具 场景
BlockingQueue 生产者消费者
CountDownLatch 等待多个任务完成
CyclicBarrier 多线程互相等待到屏障
Semaphore 控制并发许可数
CompletableFuture 异步任务编排

优先使用高层并发工具,少直接写 wait/notify。

# Tips 快问快答

Q:wait 为什么必须在 synchronized 中调用? A:线程必须持有对象 monitor,才能释放它并进入 WaitSet。

Q:wait 会释放锁吗? A:会释放当前对象的 monitor。

Q:sleep 会释放锁吗? A:不会。

Q:notify 后线程会立即执行吗? A:不会,被唤醒线程还要重新竞争锁。

Q:为什么等待条件用 while? A:防止虚假唤醒和条件被其他线程改变。

Q:notify 和 notifyAll 怎么选? A:复杂条件优先 notifyAll,避免唤醒错误线程。

Q:生产者消费者推荐手写 wait/notify 吗? A:不推荐,优先使用 BlockingQueue。

Q:Condition 相比 wait/notify 有什么优势? A:可以为一把锁创建多个条件队列,唤醒更精准。

上次更新: 2026/06/24, 17:22:59
Java内存模型(JMM)
线程池

← Java内存模型(JMM) 线程池→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式