在 Java 中,wait()
和 notify()
方法是用于线程间通信的基本机制,它们可以协调多个线程之间的协作。这些方法都属于 Object
类,因此可以在任何对象上调用。下面详细介绍它们的使用方法和原理。
wait()
方法
wait()
方法用于让当前线程进入等待状态,直到另一个线程调用同一个对象的 notify()
或 notifyAll()
方法来唤醒它。wait()
方法必须在同步块或同步方法中调用,否则会抛出 IllegalMonitorStateException
异常。
示例
class SharedResource {
public synchronized void waitMethod() {
try {
System.out.println(Thread.currentThread().getName() + " is waiting.");
wait();
System.out.println(Thread.currentThread().getName() + " is resumed.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void notifyMethod() {
System.out.println(Thread.currentThread().getName() + " is notifying.");
notify();
}
}
public class WaitNotifyExample {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread thread1 = new Thread(resource::waitMethod, "Thread 1");
Thread thread2 = new Thread(resource::notifyMethod, "Thread 2");
thread1.start();
try {
Thread.sleep(1000); // Ensure thread1 starts and waits
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
}
}
notify()
方法
notify()
方法用于唤醒一个正在等待该对象监视器的线程。如果有多个线程在等待,那么 notify()
将随机唤醒其中一个线程。被唤醒的线程必须重新获取对象的监视器锁,才能继续执行。
notifyAll()
方法
notifyAll()
方法用于唤醒所有等待该对象监视器的线程。被唤醒的线程将会竞争对象的监视器锁,只有一个线程能成功获得锁并继续执行,其他线程会继续等待。
示例
class SharedResource {
public synchronized void waitMethod() {
try {
System.out.println(Thread.currentThread().getName() + " is waiting.");
wait();
System.out.println(Thread.currentThread().getName() + " is resumed.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void notifyAllMethod() {
System.out.println(Thread.currentThread().getName() + " is notifying all.");
notifyAll();
}
}
public class WaitNotifyAllExample {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread thread1 = new Thread(resource::waitMethod, "Thread 1");
Thread thread2 = new Thread(resource::waitMethod, "Thread 2");
Thread thread3 = new Thread(resource::notifyAllMethod, "Thread 3");
thread1.start();
thread2.start();
try {
Thread.sleep(1000); // Ensure thread1 and thread2 start and wait
} catch (InterruptedException e) {
e.printStackTrace();
}
thread3.start();
}
}
注意事项
- 必须在同步块中调用:
wait()
、notify()
和notifyAll()
必须在同步块或同步方法中调用,因为它们需要持有对象的监视器锁。 - 释放锁:调用
wait()
方法时,线程会释放对象的监视器锁,进入等待状态。被唤醒后,线程需要重新获得监视器锁,才能继续执行。 - 唤醒顺序不确定:
notify()
随机唤醒一个等待的线程,而notifyAll()
唤醒所有等待的线程,唤醒的顺序取决于线程调度器。
总结
wait()
:让线程进入等待状态,释放监视器锁。notify()
:唤醒一个正在等待该对象监视器的线程。notifyAll()
:唤醒所有正在等待该对象监视器的线程。
这些方法在多线程编程中非常重要,可以实现线程间的协作和通信。通过合理使用 wait()
和 notify()
方法,可以避免竞争条件和死锁等问题,编写出更加健壮的多线程应用程序。