线程间通信方式
在Java多线程编程中,线程间通信(Inter-Thread Communication)是协调多个线程协同工作的核心技术。以下是主要通信方式及其应用:
1. wait()/notify()/notifyAll()
一、是什么?
Object类提供的原生方法:
wait()
:释放锁并阻塞当前线程,等待唤醒。notify()
:随机唤醒一个等待线程。notifyAll()
:唤醒所有等待线程。
二、解决什么问题
解决线程在共享资源上的等待/通知问题,避免忙等待(busy-waiting),减少CPU浪费。
三、核心方法
synchronized (lock) {
while (条件不满足) {
lock.wait(); // 释放锁并等待
}
// 执行业务
lock.notifyAll(); // 唤醒其他线程
}
四、应用场景
生产者-消费者模型(如任务队列)、线程按顺序执行。
五、重要注意事项
- 必须在
synchronized
块内调用,否则抛IllegalMonitorStateException
。 - 推荐用
while
代替if
检查条件,防止虚假唤醒(spurious wakeup)。
2. Lock与Condition(JDK5+)
一、是什么?java.util.concurrent.locks.Lock
接口替代synchronized
,Condition
提供更灵活的等待/通知机制。
二、解决什么问题
解决synchronized
无法中断、超时等限制,支持多条件队列(如读写锁)。
三、核心方法
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
try {
while (条件不满足) {
condition.await(); // 类似wait()
}
// 执行业务
condition.signalAll(); // 类似notifyAll()
} finally {
lock.unlock();
}
四、应用场景
复杂同步需求(如阻塞队列实现)、高性能并发控制。
五、重要注意事项
- 必须手动释放锁(
unlock()
),通常放在finally
块。 Condition
支持多个等待队列(如生产者/消费者独立唤醒)。
3. 阻塞队列(BlockingQueue)
一、是什么?java.util.concurrent.BlockingQueue
接口,线程安全的队列,提供阻塞式插入/移除。
二、解决什么问题
简化生产者-消费者模型,避免手动实现wait/notify
逻辑。
三、核心方法
put(E e)
:队列满时阻塞插入。take()
:队列空时阻塞移除。
四、应用场景
线程池任务队列、数据管道(如日志处理)。
五、Java示例
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
// 生产者
queue.put("data"); // 阻塞直到空间可用
// 消费者
String data = queue.take(); // 阻塞直到数据可用
4. 并发工具类(JDK5+)
一、CountDownLatch
- 是什么? 计数器锁,线程等待其他线程完成。
- 场景:主线程等待所有子线程初始化完成。
CountDownLatch latch = new CountDownLatch(3);
latch.countDown(); // 子线程调用
latch.await(); // 主线程阻塞等待
二、CyclicBarrier
- 是什么? 循环屏障,线程相互等待至指定数量。
- 场景:多阶段并行计算(如MapReduce)。
三、Semaphore
- 是什么? 信号量,控制资源访问并发数。
- 场景:数据库连接池限流。
5. volatile变量
一、是什么?
轻量级同步机制,保证变量可见性(直接读写主内存)。
二、解决什么问题
解决多线程环境下共享变量的可见性问题(非原子性)。
三、应用场景
状态标志位(如volatile boolean running
),双重检查锁定(Double-Checked Locking)。
四、重要注意事项
- 不保证原子性(如
i++
需配合synchronized
或原子类)。
关键区别
方式 | 特点 | 适用场景 |
---|---|---|
wait/notify | 需synchronized ,基础但易出错 | 简单同步控制 |
Lock/Condition | 灵活,支持多条件 | 复杂同步逻辑 |
BlockingQueue | 封装线程安全,开箱即用 | 生产者-消费者模型 |
CountDownLatch | 一次性等待 | 主线程等待子线程初始化 |
volatile | 仅保证可见性,非互斥 | 状态标志、双重检查锁定 |
总结
- 简单同步 →
wait/notify
或volatile
标志位。 - 复杂同步 →
Lock/Condition
或并发工具类。 - 解耦生产消费 → 优先用
BlockingQueue
。 - 线程协作 →
CountDownLatch
/CyclicBarrier
。 - JDK8+优化:优先使用
java.util.concurrent
包下的类(如CompletableFuture
),避免手动实现底层同步。
注意:避免底层
wait/notify
的复杂性,高并发场景推荐BlockingQueue
或并发工具类,减少出错概率并提升可维护性。