在 java 中,synchronized 和 wait/notify 配合使用的核心在于:必须将 wait() 和 notify() 调用包裹在 synchronized 块内,且锁对象必须一致。这样做是为了确保线程在检查条件、进入等待或唤醒其他线程时,共享状态是线程安全的,从而避免竞态条件和“丢失信号”的问题。

synchronized 如何与 wait 配合实现线程等待
当线程需要等待某个条件满足时,它必须在持有锁的情况下调用 wait()。这会导致当前线程释放锁并进入等待状态,直到被其他线程唤醒。关键在于,wait() 必须在 while 循环中使用,以处理虚假唤醒(spurious wakeup)的情况。

public class WaitExample {
private boolean condition = false;
public void waitForCondition() throws InterruptedException {
synchronized (this) {
while (!condition) {
this.wait(); // 释放锁并等待
}
System.out.println("Condition met, proceeding...");
}
}
public void setCondition() {
synchronized (this) {
this.condition = true;
this.notify(); // 唤醒一个等待线程
}
}
}上述代码展示了标准的等待模式。waitForCondition 方法首先获取当前对象的锁,然后检查 condition 变量。如果条件不满足,它调用 wait(),此时线程会释放锁并挂起。setCondition 方法获取锁后修改条件并调用 notify(),这会唤醒一个正在等待的线程。注意,notify() 不会立即释放锁,只有当 synchronized 块执行完毕时,锁才会被释放,等待线程才能重新竞争锁。
立即学习“Java免费学习笔记(深入)”;
synchronized 如何与 notify 配合实现线程唤醒
notify() 用于唤醒一个正在等待该对象锁的线程。同样,notify() 也必须在 synchronized 块内调用。notifyAll() 可以唤醒所有等待线程,通常更安全,但可能导致不必要的上下文切换。选择 notify() 还是 notifyAll() 取决于具体场景:如果只有一个线程能处理通知,使用 notify();如果有多个线程可能感兴趣,使用 notifyAll()。

public class NotifyExample {
private final Object lock = new Object();
private int count = 0;
public void incrementAndNotify() {
synchronized (lock) {
count++;
if (count == 5) {
lock.notifyAll(); // 唤醒所有等待线程
}
}
}
public void waitForCount() throws InterruptedException {
synchronized (lock) {
while (count < 5) {
lock.wait();
}
System.out.println("Count reached 5");
}
}
}这个例子演示了 notifyAll() 的使用。incrementAndNotify 方法在 count 达到 5 时调用 notifyAll(),唤醒所有在 lock 上等待的线程。waitForCount 方法则持续等待直到 count >= 5。使用 notifyAll() 可以避免因只唤醒错误线程而导致的死锁或无限等待。在实际开发中,应优先使用 notifyAll(),除非明确知道只有一个线程需要被唤醒。
基于程序中某个输入、条件或结果的具体问题
在上述代码中,如果多个线程同时调用 waitForCount,它们都会进入等待状态。当 count 达到 5 时,notifyAll() 会唤醒所有等待线程。这些线程会重新竞争锁,一旦获得锁,它们会再次检查条件(while 循环),发现条件已满足,然后继续执行。这种机制确保了所有相关线程都能正确响应条件变化,避免了遗漏通知的问题。


















