首页 技术 正文
技术 2022年11月17日
0 收藏 533 点赞 3,313 浏览 1646 个字

做 Java 开发的小伙伴,对 wait 方法和 notify 方法应该都比较熟悉,这两个方法在线程通讯中使用的频率非常高,但对于 notify 方法的唤醒顺序,有很多小伙伴的理解都是错误的,有很多人会认为 notify 是随机唤醒的,但它真的是随机唤醒的吗?

带着这个疑问,我们尝试休眠 100 个线程,再唤醒 100 个线程,并把线程休眠和唤醒的顺序保持到两个集合中,最后再打印一下这两个集合,看一下它们的执行顺序,如果它们的顺序是一致的,那说明 notify 是顺序唤醒的,否则则是随机唤醒的,notify 测试代码如下:

import java.util.ArrayList;
import java.util.List;public class NotifyExample {
// 保存休眠线程的顺序
private static List<String> waitList = new ArrayList<>();
// 保存唤醒线程的顺序
private static List<String> notifyList = 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 会按照线程的休眠顺序,依次唤醒线程。

是非审之于己,毁誉听之于人,得失安之于数。

公众号:Java面试真题解析

面试合集:https://gitee.com/mydb/interview

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,085
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,560
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,409
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,182
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,819
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,902