为什么Java中notify()仅唤醒最后调用wait()的线程而非最先调用的?
问题根因
Java语言规范从未要求notify()方法按照线程调用wait()的先后顺序唤醒等待线程,具体唤醒策略完全由JVM实现决定。你使用的OpenJDK/OracleJDK默认的HotSpot虚拟机,notify()默认采用非公平唤醒策略,会优先唤醒距离当前时间最近、刚进入等待队列的线程,这就是你观测到先调用wait()的线程拿不到唤醒机会、出现饥饿的核心原因。
你代码中两个线程互相唤醒的现象是该策略的典型表现:持有锁的线程调用notify()之后会立即调用wait()释放锁,此时刚进入等待队列的线程会被优先唤醒,几次循环后就会形成两个线程固定互唤醒的闭环,剩下的线程始终无法被选中。
你遇到的现象和Windows 10操作系统、JDK 15版本没有直接关联,切换其他版本的HotSpot JDK大概率也会复现同样的问题。
解决方案
如果需要实现严格按等待顺序唤醒的公平策略,可以选择以下两种修改方案:
- 把
notify()替换为notifyAll():每次唤醒所有等待在该锁对象上的线程,所有线程共同抢占锁,可解决饥饿问题,但会产生大量无效唤醒的性能开销,仅适合小并发量的场景。 - 改用公平模式的
ReentrantLock配合Condition实现等待通知:初始化ReentrantLock时设置fair = true开启公平模式,配套的Condition对象的signal()方法会严格按照线程进入等待队列的顺序唤醒,不会出现饥饿问题,性能也更稳定。
公平实现的核心示例代码如下:
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Main { public static final int t_count = 4; // 替换原内置锁,开启公平模式 public static final ReentrantLock lock = new ReentrantLock(true); public static final Condition condition = lock.newCondition(); public static volatile int id = 0; public static void main(String[] args) throws InterruptedException { Thread t[] = new Thread[t_count]; for (int i = 0; i < t_count; i++) { t[i] = new MyThread(); t[i].setUncaughtExceptionHandler((t1, e) -> e.printStackTrace()); t[i].start(); } t[t_count - 1].join(); } public static class MyThread extends Thread { static int integer = 0; static int count = 0; int i; public MyThread() { i = integer++; System.out.println(i + " initial" + " " + this); } @Override public void run() { try { lock.lock(); while (true) { System.out.println(i + " is here"); count += 1; if (count >= 40) { condition.signal(); System.out.println(i + " return"); return; } if (id == i) { System.out.println(i + " do work"); System.out.flush(); id = (id + 1) % t_count; } System.out.println(i + " notify"); condition.signal(); System.out.println(i + " wait"); condition.await(); System.out.println(i + " notified"); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } }
内容的提问来源于stack exchange,提问作者desperateLord
相关产品推荐
相关产品推荐

