@IntrinsicCandidate

public final native void notify();

是 Java 中 Object 类的一个 native 方法,用于实现线程间的通信机制。它在 Java 多线程编程中扮演重要角色,是 wait/notify 机制的一部分。


🔍 方法说明

@IntrinsicCandidate
public final native void notify();
  • 作用:唤醒一个正在等待该对象监视器(monitor)的线程。
  • 访问权限final 表示不能被重写;native 表示由 JVM 底层实现。
  • 使用前提:必须在 synchronized 块或方法中调用,否则抛出 IllegalMonitorStateException
  • 唤醒行为:从所有因调用 wait() 而阻塞在该对象上的线程中随机选择一个进行唤醒(不是按优先级或顺序)。

🧠 notify() 的语义理解

Java 中的 notify()wait() 都基于 对象的监视器(monitor) 实现:

  • 每个 Java 对象都有一个与之关联的 监视器锁(monitor lock)
  • 当多个线程调用 wait() 时,它们会进入该对象的 等待集合(wait set)
  • 调用 notify() 会从这个等待集合中唤醒一个线程(不保证顺序),使其可以重新竞争对象的锁。

⚙️ 底层实现原理

1. JVM 内部结构

JVM 使用以下核心机制来支持 notify()

组件 描述
ObjectMonitor 每个 Java 对象内部有一个 monitor 结构,负责管理锁和线程等待/通知
Wait Set 存放调用了 wait() 的线程
Entry Set / Contentions List 管理试图获取锁但未成功的线程

2. C++ 层面的实现(HotSpot JVM)

在 OpenJDK 的 HotSpot 虚拟机中,notify() 的底层实现在 C++ 的 objectMonitor.cpp 文件中。

核心流程如下:
  1. 检查当前线程是否持有对象锁
    • 如果没有持有锁,抛出 IllegalMonitorStateException
  2. 查找是否有线程在 Wait Set 中等待
    • 如果有,则从中移除一个线程,并将其放入 Entry Set 或直接唤醒以重新竞争锁
  3. 唤醒线程
    • 使用操作系统提供的线程调度机制(如 Linux 上的 futex、Windows 上的 Event/Condition Variable)进行唤醒操作
示例伪代码(简化版):
void ObjectMonitor::notify(TRAPS) {
    if (current_thread != owner()) {
        THROW(vmSymbols::java_lang_IllegalMonitorStateException());
    }

    if (wait_set_head == NULL) {
        return; // 没有线程在等待
    }

    Thread* notified = remove_from_wait_set(wait_set_head);
    add_to_entry_set(notified); // 放入 entry set 等待锁
}

📦 @IntrinsicCandidate 注解的作用

@IntrinsicCandidate 是 JDK 9 引入的一个注解,表示该方法可能被 JVM 内联优化(intrinsic),即在某些情况下 JVM 可能不会真正调用 native 函数,而是直接在 JIT 编译时替换为更高效的机器指令。

但这并不改变其语义和功能。


🧪 使用示例

public class NotifyExample {
    private static final Object lock = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread waiting...");
                try {
                    lock.wait(); // 等待通知
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread awakened!");
            }
        }).start();

        try {
            Thread.sleep(1000); // 主线程等待子线程进入 wait
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (lock) {
            lock.notify(); // 唤醒一个等待线程
        }
    }
}

📌 注意事项

项目 说明
必须配合 synchronized 使用 否则抛出异常
无法控制唤醒哪个线程 JVM 随机选择一个线程唤醒
唤醒后仍需重新获取锁 即使被唤醒,线程也必须重新竞争 monitor 锁才能继续执行
不能保证立即执行 被唤醒的线程只是进入可运行状态,何时调度取决于线程调度器
避免虚假唤醒 推荐使用 while 循环判断条件,而不是 if 判断

✅ 总结

特性 描述
方法签名 public final native void notify();
作用 唤醒一个在对象上等待的线程
依赖机制 对象监视器(monitor)、wait set
底层实现 JVM 使用 ObjectMonitor 管理线程等待与唤醒
调用限制 必须在 synchronized 块内调用
线程安全 安全,但需注意条件变量的同步问题
典型用途 多线程协作、生产者-消费者模型、任务调度等场景

理解 notify() 的底层实现有助于更好地掌握 Java 并发编程的核心机制,也能帮助开发者写出更健壮、高效的并发程序。如果你对 JVM 内部机制感兴趣,可以进一步研究 objectMonitor.hppobjectMonitor.cpp 源码。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐