从“干瞪眼“到精准唤醒:Java线程通信的打怪升级之路
在Java的世界里,线程就像一群忙碌的工人。有时候,这些工人需要互相传递消息、协调工作进度,这就是线程通信要解决的问题。今天我们就来聊聊Java线程通信从古老的wait/notify
,到现代化的Condition
,这一路是如何进化的。
一、原始时代:wait/notify
的"信号枪"
想象有两个工人:工人A负责生产面包,工人B负责包装面包。工人A生产完面包后,要告诉工人B可以开始包装了;工人B包装完,也要通知工人A可以继续生产了。
在Java里,我们可以用wait/notify
来实现这个过程。wait
方法就像工人暂时放下手头工作去休息,notify
方法就像吹响信号枪,唤醒正在休息的工人。
public class WaitNotifyExample {private static final Object lock = new Object();private static boolean hasProduct = false;public static void main(String[] args) {// 生产者线程new Thread(() -> {while (true) {synchronized (lock) {while (hasProduct) {try {lock.wait(); // 没有包装完,等待} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("生产了一个面包");hasProduct = true;lock.notify(); // 通知包装工人}}}).start();// 消费者线程new Thread(() -> {while (true) {synchronized (lock) {while (!hasProduct) {try {lock.wait(); // 没有面包,等待} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("包装了一个面包");hasProduct = false;lock.notify(); // 通知生产工人}}}).start();}
}
但wait/notify
有个很大的问题:notify只能随机唤醒一个等待的线程。如果有多个不同类型的线程在等待,很可能唤醒的不是我们想要的那个,这就像在操场上随便喊一嗓子,不知道谁会回应。
二、新时代:Condition
的"私人对讲机"
为了解决wait/notify
的问题,Java引入了Condition
接口,它就像给每个工人配备了一个私人对讲机。每个Condition
对象都可以管理一组线程,我们可以精准地唤醒特定的线程。
Condition
通常和Lock
接口一起使用,代替传统的synchronized
关键字。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ConditionExample {private static final Lock lock = new ReentrantLock();private static final Condition hasProductCondition = lock.newCondition();private static boolean hasProduct = false;public static void main(String[] args) {// 生产者线程new Thread(() -> {while (true) {lock.lock();try {while (hasProduct) {hasProductCondition.await(); // 没有包装完,等待}System.out.println("生产了一个面包");hasProduct = true;hasProductCondition.signal(); // 通知包装工人} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}).start();// 消费者线程new Thread(() -> {while (true) {lock.lock();try {while (!hasProduct) {hasProductCondition.await(); // 没有面包,等待}System.out.println("包装了一个面包");hasProduct = false;hasProductCondition.signal(); // 通知生产工人} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}).start();}
}
Condition
的await
方法就像工人通过对讲机说"我先休息了",signal
方法就像通过对讲机精准呼叫特定的工人。相比wait/notify
,Condition
提供了更灵活、更精准的线程通信方式。
三、总结:为什么要进化?
从wait/notify
到Condition
,Java线程通信的进化主要解决了以下几个问题:
- 精准唤醒:
Condition
可以精准唤醒特定的线程,避免无效唤醒 - 多个等待队列:一个
Lock
可以创建多个Condition
,管理不同类型的线程 - 更灵活的操作:
Condition
配合Lock
使用,比synchronized
更灵活
对于初学者来说,wait/notify
简单直接,但功能有限;Condition
虽然复杂一些,但在处理复杂多线程场景时更得心应手。随着学习的深入,大家会发现Condition
的强大之处。
希望通过这篇文章,能让大家对Java线程通信的进化有一个清晰的认识。下次遇到多线程通信的问题,就知道该用哪个工具啦!