在Java中,多线程编程是一种常见的方式,可以让程序更高效地运行。为了有效地控制线程之间的协作,Java提供了等待唤醒机制(即wait()
和notify()
方法)。这使得一个线程可以在某种条件不满足时暂停执行,并在其他线程满足条件时被唤醒执行。
等待唤醒机制的基本原理
在Java中,wait()
和notify()
方法是定义在Object
类中,因此任何Java对象都可以作为锁。通过这些方法,线程可以在某种条件下挂起,直到其他线程调用同一个对象的notify()
或notifyAll()
方法将其唤醒。
wait() 方法
当一个线程调用wait()
方法时,它会释放当前对象的监视器锁,并进入等待状态,直到其他线程调用该对象的notify()
或notifyAll()
方法。需要注意的是,wait()
方法必须在同步代码块中调用。
notify() 方法
notify()
方法用于唤醒在此对象监视器上等待的单个线程。如果有多个线程在等待,Java会选择一个线程唤醒。notifyAll()
则会唤醒所有等待的线程。
代码示例
下面是一个简单的生产者-消费者模型的示例,展示如何使用wait()
和notify()
来实现等待唤醒机制。
import java.util.LinkedList;
import java.util.Queue;
class DataBuffer {
private final Queue<Integer> buffer = new LinkedList<>();
private final int limit = 10;
public synchronized void produce(int value) throws InterruptedException {
// 如果缓冲区满,则等待
while (buffer.size() == limit) {
wait();
}
buffer.add(value);
System.out.println("生产者生产: " + value);
// 通知消费者可以消费
notify();
}
public synchronized int consume() throws InterruptedException {
// 如果缓冲区为空,则等待
while (buffer.isEmpty()) {
wait();
}
int value = buffer.poll();
System.out.println("消费者消费: " + value);
// 通知生产者可以生产
notify();
return value;
}
}
class Producer implements Runnable {
private final DataBuffer dataBuffer;
public Producer(DataBuffer dataBuffer) {
this.dataBuffer = dataBuffer;
}
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
dataBuffer.produce(i);
Thread.sleep(100); // 模拟生产时间
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
class Consumer implements Runnable {
private final DataBuffer dataBuffer;
public Consumer(DataBuffer dataBuffer) {
this.dataBuffer = dataBuffer;
}
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
dataBuffer.consume();
Thread.sleep(150); // 模拟消费时间
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public class WaitNotifyExample {
public static void main(String[] args) {
DataBuffer dataBuffer = new DataBuffer();
Thread producerThread = new Thread(new Producer(dataBuffer));
Thread consumerThread = new Thread(new Consumer(dataBuffer));
producerThread.start();
consumerThread.start();
try {
producerThread.join();
consumerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
代码解析
-
数据缓冲区(DataBuffer):这是生产者和消费者共享的资源,使用一个
Queue
(队列)来存储数据,限制其大小(limit = 10
)。 -
生产者(Producer):不断产生数据,将其放入缓冲区。如果缓冲区满,则调用
wait()
方法进入等待状态,直到消费者消费了某些数据并调用notify()
唤醒生产者。 -
消费者(Consumer):不断从缓冲区消费数据。如果缓冲区为空,则调用
wait()
方法进入等待状态,直到生产者生产了数据并调用notify()
唤醒消费者。 -
主程序(main 方法):创建生产者和消费者线程,启动后,主程序等待这两个线程完成。
结论
通过使用wait()
和notify()
方法,Java程序设计者可以实现复杂的线程协作机制,将多个线程之间的关系管理得更加高效与清晰。这个机制在实际开发中随处可见,比如服务器的任务调度、数据处理等场景中都有其身影。