Java中notify是顺序唤醒还是随机唤醒的

前言:

做 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中notify是顺序唤醒还是随机唤醒的的文章就介绍到这了,更多相关Java notify唤醒规则内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java多线程基础 线程的等待与唤醒(wait、notify、notifyAll)

    本篇我们来研究一下 wait() notify() notifyAll() . DEMO1: wait() 与 notify() public class Test { static class ThreadOne extends Thread { private Callback mCallback; @Override public void run() { work(); if (mCallback != null) { mCallback.onResult(false); } } //

  • Java wait和notify虚假唤醒原理

    自己在此记录一下,方便日后复习. 虚假唤醒的概念 jdk官方文档解释: 所以说在wait和notify一块使用时,如果使用if作为条件时,会有虚假唤醒的情况发生,所以必须使用while作为循环条件.下面来举例实验: 首先,创建一个资源类:(在多线程中,一般都是资源类和线程操作解耦,不放在用同一个类中,只有在线程操作资源类时,才会创建资源类的对象) package com.test; /** * 资源类 * @author Huxudong * @createTime 2020-04-01 21:

  • Java线程中的notifyAll唤醒操作(推荐)

    注意: java中的notifyAll和notify都是唤醒线程的操作,notify只会唤醒等待池中的某一个线程,但是不确定是哪一个线程,notifyAll是针对指定对象里面的所有线程执行唤醒操作,指定对象一旦唤醒成功.则会立即加入线程的资源争夺中去. 例如: package TestThread.ThreadSynchronized; public class TestWaitAll { public static void main(String[] args) { Test1 test1

  • Java中notify是顺序唤醒还是随机唤醒的

    前言: 做 Java 开发的小伙伴,对 wait 方法和 notify 方法应该都比较熟悉,这两个方法在线程通讯中使用的频率非常高,但对于 notify 方法的唤醒顺序,有很多小伙伴的理解都是错误的,有很多人会认为 notify 是随机唤醒的,但它真的是随机唤醒的吗? 带着这个疑问,我们尝试休眠 100 个线程,再唤醒 100 个线程,并把线程休眠和唤醒的顺序保持到两个集合中,最后再打印一下这两个集合,看一下它们的执行顺序,如果它们的顺序是一致的,那说明 notify 是顺序唤醒的,否则则是随机

  • Java中notify()和notifyAll()的使用区别

    notify() 和 notifyAll() 有什么区别? 先解释两个概念. 等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池,等待池中的线程不会去竞争该对象的锁. 锁池:只有获取了对象的锁,线程才能执行对象的 synchronized 代码,对象的锁每次只有一个线程可以获得,其他线程只能在锁池中等待 然后再来说notify和notifyAll的区别 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程

  • Java中notify和notifyAll的区别及何时使用

    提几个问题,从问题中去了解去学习: 他们之间有啥区别? 如果我使用notify(),将通知哪个线程? 我怎么知道有多少线程在等待,所以我可以使用notifyAll()? 如何调用notify()? 什么是这些线程等待被通知等? 我给点建议:建议使用jdk8里的lock包 java.util.concurrent.locks下的Condition 他可以支持唤醒指定的线程. 他只是一个接口 具体实现类是在AbstractQueuedSynchronizer 也就是AQS框架里的 你可以自己继承他

  • Java中保证线程顺序执行的操作代码

    只要了解过多线程,我们就知道线程开始的顺序跟执行的顺序是不一样的.如果只是创建三个线程然后执行,最后的执行顺序是不可预期的.这是因为在创建完线程之后,线程执行的开始时间取决于CPU何时分配时间片,线程可以看成是相对于的主线程的一个异步操作. public class FIFOThreadExample { public synchronized static void foo(String name) { System.out.print(name); } public static void

  • Java中ArrayList与顺序表的概念与使用实例

    目录 前言 泛型(Generic) 泛型的引入 泛型的基本概念 包装类(Wrapper Class) 包装类的引入 基本数据类型与包装类的对应关系 ArrayList与顺序表 ArrayList简介 ArrayList使用 ArrayList的构造 ArrayList常见方法 ArrayList的遍历 总结 前言 通过前面的博客我们已经大致了解了关于Java的基本知识,而下面的几篇博客我们着重开始对于数据结构的知识进行学习,这篇博客我们就了解关于顺序表和ArrayList的相关知识,从名字上我们

  • Java中ArrayList与顺序表的定义与实现方法

    目录 1.线性表 定义 特征 2.顺序表 定义 实现 打印数组 新增元素 判断是否包含某个元素 查找元素 获取pos位置的元素 更改pos位置的值 删除操作 获取顺序表长度 清空顺序表 3.ArrayList 简介: 使用 一些常见方法 ArrayList的遍历 总结 1.线性表 定义 线性表是最基本.最简单.也是最常用的一种数据结构.线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列. 常见的线性表:顺序表.链表.栈.队列... 线性表在逻辑上是

  • Java中对象初始化顺序的详细介绍

    前言 在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.最近我发现了一个有趣的问题,这个问题的答案乍一看下骗过了我的眼睛.看一下这三个类: package com.ds.test; public class Upper { String upperString; public Upper() { Initializer.initialize(this); } } package com.ds.test; public class Lower extends

  • Java中try-catch-finally执行顺序你知道吗

    目录 引言 正文 try块中有return catch块中有return try块和finally块中有return catch块和finally块中有return try块.catch块和finally块中都有return 总结 引言 java异常处理中,try.catch.finally的执行顺序,大家都知道是按顺序执行的,这里我就不废话了.但是当try.catch.finally中加入return之后,就会有几种不同的情况出现,下面分别来说明一下.也可以跳到最后直接看总结. 正文 这里共列

  • Java中的逻辑结构详解

    Java中的逻辑结构 逻辑结构 Java中的逻辑结构 顺序结构分支结构循环结构 顺序结构 顺序结构顾名思义,就是按照代码的顺序依次往下执行,这个不必多讲 分支结构 分支结构又可以细分为两个: if-else-这两个单词相信都认识,翻译成中文就是我们平时所说的如果-就-,那么在Java中该怎么用呢: ①:if else: 它的基本语法结构如下: if(判断条件){ 语句1: }else{ 语句2: 当判断条件为真的时候,执行语句1,否则执行语句2 示例: import java.util.*; p

  • Java中线程的等待与唤醒_动力节点Java学院整理

    wait(), notify(), notifyAll()等方法介绍 在Object.java中,定义了wait(), notify()和notifyAll()等接口.wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁.而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程:notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程. Object类中关于等待/唤醒的API详细信息如下: notify()      

随机推荐