You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何notifyAll()会引发线程饥饿?我的Java代码为何仅两线程运行?

问题分析与解答

你的代码

class Shared {
    private static int index = 0;
    public synchronized void printThread() {
        try {
            while(true) {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + ": " + index++);

            notifyAll();
//            notify();
                wait();
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Example13 implements Runnable {
    private Shared shared = new Shared();

    @Override
    public void run() {
        shared.printThread();
    }
}

public class tetest {
    public static void main(String[] args) {
        Example13 r = new Example13();
        Thread t1 = new Thread(r, "Thread 1");
        Thread t2 = new Thread(r, "Thread 2");
        Thread t3 = new Thread(r, "Thread 3");
        Thread t4 = new Thread(r, "Thread 4");
        Thread t5 = new Thread(r, "Thread 5");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}

运行结果

Thread 1: 0
Thread 5: 1
Thread 4: 2
Thread 3: 3
Thread 2: 4
Thread 3: 5
Thread 2: 6
Thread 3: 7
Thread 2: 8
Thread 3: 9

为什么最后只剩两个线程在运行?

这不是严格意义上的线程饥饿(饥饿指线程永久无法获得执行资源),而是操作系统线程调度的偏好加上Java内置锁的非公平特性导致的:

  • 调度的缓存亲和性:操作系统为了降低上下文切换开销,会优先让最近执行过的线程再次获得CPU时间片——这些线程的上下文(寄存器、栈数据等)还在CPU缓存中,复用它们能提升整体性能。当你的线程调用wait()释放锁后,所有被唤醒的线程会竞争锁,操作系统更倾向于把锁分配给刚执行完的线程(比如示例中的Thread3和Thread2)。
  • 内置锁的非公平性:Java的synchronized锁是非公平的,它不保证等待时间最长的线程优先获得锁。即使你用notifyAll()唤醒了所有等待线程,锁最终还是会被调度器偏好的线程抢走,其他线程只能继续等待。

为什么notify()和notifyAll()结果一致?

  • notify()是随机唤醒一个等待线程,但在你的场景里,调度器本来就偏好那两个线程,所以每次唤醒的大概率是它们中的一个。
  • notifyAll()会唤醒所有等待线程,但这些线程还是要竞争同一把锁,最终只有一个能拿到,而调度器还是会优先选择那两个“热线程”,所以结果看起来和notify()没区别。

怎么让所有线程轮流执行?

如果想实现公平的线程调度,可以用java.util.concurrent.locks.ReentrantLock的公平锁模式,它会按照线程等待的顺序分配锁:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

class Shared {
    private static int index = 0;
    private final ReentrantLock lock = new ReentrantLock(true); // 启用公平锁
    private final Condition condition = lock.newCondition();

    public void printThread() {
        try {
            lock.lock();
            while (true) {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + ": " + index++);
                condition.signalAll();
                condition.await();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

使用公平锁后,线程会按照等待顺序轮流获得锁,不会出现某几个线程独占资源的情况。

内容的提问来源于stack exchange,提问作者HongPro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 04:15:29