 
 作者 | 磊哥 来源 | Java面试真题解析(ID:aimianshi666) 转载请联系授权(微信ID:GG_Stone) 做 Java 开发的面试小伙伴,对 wait 方法和 notify 方法应该都比较熟悉,突击这两个方法在线程通讯中使用的随机频率非常高,但对于 notify            方法的唤醒唤醒顺序,有很多小伙伴的面试理解都是错误的,有很多人会认为 notify 是突击随机唤醒的,但它真的随机是随机唤醒的吗? 带着这个疑问,我们尝试休眠 100 个线程,唤醒再唤醒 100            个线程,面试并把线程休眠和唤醒的突击顺序保持到两个集合中,最后再打印一下这两个集合,随机看一下它们的唤醒执行顺序,如果它们的面试顺序是一致的,那说明 notify            是突击顺序唤醒的,否则则是随机随机唤醒的源码下载,notify 测试代码如下: import java.util.ArrayList; import java.util.List; public class NotifyExample { // 保存休眠线程的顺序 private static ListwaitList = new ArrayList<>(); // 保存唤醒线程的顺序 private static ListnotifyList = new ArrayList<>(); public static void main(String[] args) throws InterruptedException { final Object lock = new Object(); // 休眠 100 个线程 for (int i = 0; i < 100; i++) { String threadName = Integer.toString(i); // 定义线程名 new Thread(() -> { // 获取当前执行线程的线程名 String currThreadName = Thread.currentThread().getName(); synchronized (lock) { waitList.add(currThreadName); // 存入等待 list try { lock.wait(); // 休眠线程 } catch (InterruptedException e) { e.printStackTrace(); } notifyList.add(currThreadName); // 存储唤醒 list } }, threadName).start(); } Thread.sleep(1000); // 唤醒 100 个线程 for (int i = 0; i < 100; i++) { synchronized (lock) { lock.notify(); // 唤醒线程 } } // 打印 2 个线程列表 System.out.println("等待线程顺序:" + waitList); System.out.println("唤醒线程顺序:" + waitList); } }以上程序的执行结果如下图所示:             从上述打印的结果我们可以看出,使用 notify            并不是随机唤醒的,而是顺序唤醒的,虽然以上代码能证明这个结论,但为了更清楚的解释这个问题,我们查看了 notify 的实现源码,它的源码内容如下:             简单翻译一下上面的重点内容,notify 选择唤醒的线程是任意的,但具体的实现还要依赖于            JVM。也就是说 notify 的唤醒规则,最终取决于 JVM 厂商,不同的厂商的免费源码下载实现可能是不同的,比如阿里的 JVM 和 Oracle 的 JVM,关于            notify 的唤醒规则可能是不一样的。         那作为一个普通的程序员我们要研究的就是官方的 JVM 也就是 HotSpot 虚拟机,它的 notify 实现源码在 ObjectMonitor.cpp            中,具体源码如下:  
 DequeueWaiter 方法实现的源码如下:  
 从上述源码可以看出,在进行唤醒时,每次会从 _WaitSet            等待集合中获取第一个元素进行出队操作,这也说明了 notify 是顺序唤醒的。 总结notify 唤醒线程的规则是随机唤醒还是顺序唤醒取决于 JVM 的具体实现,作为主流的 HotSpot 虚拟机中的 notify            的云服务器提供商唤醒规则是顺序的,也就是 notify 会按照线程的休眠顺序,依次唤醒线程。  |