线程的notify方法_forkjoinpool默认线程数量

线程的notify方法_forkjoinpool默认线程数量从源码角度剖析notify/notifyAll方法到底做了些什么,线程是如何唤醒的。

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

众所周知,使用notify/notifyAll方法能唤醒wait等待的线程,那么在底层源码究竟做了些什么呢?

本章内容要解决的问题

问题1:notify/nofityAll真的唤醒了线程吗?

问题2:notify/nofityAll底层逻辑是怎样的?

线程的notify方法_forkjoinpool默认线程数量

(图1-1)

带着这两个问题来具体探究一下:

在(图1-1)中,java中的notify/nofityAll方法对应c++源码jvm.cpp中的JVM_MonitorNotifyJVM_MonitorNotifyAll方法。

1.首先,进入jvm.cpp文件,查看JVM_MonitorNotify方法。

在 JVM_MonitorNotify方法中,调用了返回值为ObjectSynchronizer的notify方法(图1-2);

线程的notify方法_forkjoinpool默认线程数量

 

(图1-2)

2.再次进入方法,可以看到最终又调用了一个notify方法,继续跟进

线程的notify方法_forkjoinpool默认线程数量

 (图1-3)

 好了,在这里是真正的核心逻辑了  (图1-4):

首先有一个policy策略(默认为2),接着DequeueWaiter,从WaitSet取出ObjectWaiter节点(waitSet等待队列是一个双向循环链表,调用object.wait,会把线程包装为一个ObjectWaiter节点,然后方入这个链表中)

线程的notify方法_forkjoinpool默认线程数量

 线程的notify方法_forkjoinpool默认线程数量

  (图1-4)

 来看看DequeueWaiter的逻辑(从双向链表中取出节点)(图1-5)

​​​​​​​线程的notify方法_forkjoinpool默认线程数量

(图1-5)

重点来了…(图1-6/1-7)

根据policy策略挪动ObjectWaiter节点

根据源码可以看到,

Policy策略:

Policy=0:将ObjectWaiter放入到enteylist队列的排头位置

Policy=1:放入到entrylist队列末尾位置

Policy=2:判断entrylist是否为空,为空就放入到entrylist中,否则放入到cxq队列的排头位置(默认)

Policy=3:判断cxq是否为空,如果为空,直接放入头部,否则放入cxq队列末尾位置

其余情况:直接唤醒线程(unpark) 但这几乎是不可能的,因为jdk默认策略为2 且jvm参数不可修改(除非直接更改源码打包)

线程的notify方法_forkjoinpool默认线程数量

(图1-6)

 线程的notify方法_forkjoinpool默认线程数量

(图1-7)

至此,notify方法结束。

也就是说没有任何有关唤醒的操作。那么第一个问题答案出来了:notify/nofityAll真的唤醒了线程吗?答案是并没有。

那么什么时候唤醒线程呢?稍作回答。

先来看看notifyAll方法源码吧:

1.notifyAll调用了返回值为ObjectSynchronizer的notifyall方法(图1-2);

线程的notify方法_forkjoinpool默认线程数量

 进入看看,也是跟着调用notifyall方法,继续进入

线程的notify方法_forkjoinpool默认线程数量

好了,核心来了… (图1-8)

可以看到notifyall源码,和notify源码几乎是一样的,唯一就是多了个for死循环;

也就是说,notifyall方法其实是循环去执行notify逻辑(从waitset链表中取出节点,然后根据策略挪动节点,直至全部取出),仅此而已

 线程的notify方法_forkjoinpool默认线程数量

 (图1-8)

至此,notifyall方法结束。

=========================================================================

看完了notify/notifyall源码逻辑,其实并没有任何唤醒操作,有的仅仅是挪动节点而已;回到中间提出的问题,那么什么时候唤醒线程呢?

其实是在synchronized代码块退出后,释放锁时根据QMode策略进行唤醒的(图1-9、1-10、1-11)

也就是说在monitorexit方法中的exit方法里(部分代码)

线程的notify方法_forkjoinpool默认线程数量

(图1-9)

 线程的notify方法_forkjoinpool默认线程数量

(图1-10)

 线程的notify方法_forkjoinpool默认线程数量

 (图1-11)

 根据不同的QMode策略挪动线程并唤醒线程

再来看看具体的挪动唤醒策略:

根据QMode策略唤醒:

QMode=2,取cxq头部节点直接唤醒

QMode=3,如果cxq非空,把cxq队列放置到entrylist的尾部(顺序跟cxq一致)

QMode=4,如果cxq非空,把cxq队列放置到entrylist的头部(顺序跟cxq相反)

QMode=0,啥都不做,继续往下走(QMode默认是0)默认是0

Qmode=0的判断逻辑就是先判断entrylist是否为空,如果不为空,则取出第一个唤醒,如

果为空再从cxq里面获取第一个唤醒

最后看看唤醒的方法ExitEpilog:

线程的notify方法_forkjoinpool默认线程数量

总结:

线程的notify/nofityAll方法在jvm源码中并没有唤醒线程,而是从waitSet链表取出一个节点进行挪动(根据policy策略,默认为2,判断entrylist是否为空,为空就放入到entrylist中,否则放入到cxq队列的排头位置),等到真正出了synchronized代码块时,根据QMode策略(默认为0,啥也不做,向下继续执行;entrylist是否为空,不为空取出一个唤醒;为空,从cxq集合取出一个唤醒)​挪动节点然后唤醒

最后,附上整体示意图:

线程的notify方法_forkjoinpool默认线程数量

 notify与policy挪动策略图

线程的notify方法_forkjoinpool默认线程数量

         QMode策略唤醒示意图

最后的问题?

1. waitSet、entryList、cxq是什么?有什么作用?三大队列?

简单解释一下:

多线程的各个方法包括synchronized的实现,与三大队列息息相关。

waitSet是线程等待集合,是一个双向循环链表,调用wait方法的线程将会在里面。

entrylist是线程争抢失败的集合,是一个双向链表。

cxq多线程竞争锁是进入的集合,是一个栈结构。

线程节点在多线程环境下操作时,在三个集合中不断地转换,但同一时间只能在某一个集合中,不能多个集合同时存在。

2.线程的其他方法?

这些问题将在后续文章中解答…感谢各位的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/195970.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Android多媒体-人脸识别

    Android多媒体-人脸识别

    2021年11月23日
    43
  • 多模态融合注记_超融合泛用

    多模态融合注记_超融合泛用多模态机器学习MultiModalMachineLearning(MMML),旨在通过机器学习并处理理解多种模态信息。包括多模态表示学习MultimodalRepresentation,模态转

    2022年8月5日
    3
  • 电信系统服务器地址,电信高速dns服务器地址谁知道?

    电信系统服务器地址,电信高速dns服务器地址谁知道?丶言小午回答数:25336|被采纳数:62016-11-2200:56:35全国各地电信DNS北京DNS地址:202.96.199.133202.96.0.133202.106.0.20202.106.148.1202.97.16.195上海DNS地址:202.96.199.132202.96.199.133202.96.209.5202.96.209.6202.96.209.133天津…

    2022年7月27日
    2
  • 签名字体怎么练_练字方法练自己名字签字

    签名字体怎么练_练字方法练自己名字签字导读:今天来给大家分享【签名字体怎么练】技法来源于网络,只是分享学习一下。感谢大家的支持,如果,你在签名字体上有什么不懂的可以来询问我的。谢谢大家的浏览!签名字体怎么练1、签名也是字体造型的再创作,因此签名设计对一个人的书法水平和理解能力还是有一定要求的。在此,我建议大家可以先练习好楷书和行书。如果真的没那个天分,就好好练习数字1.2.3.4.5.6.7.8.9。为什么练习数字可以对设计签名有帮助呢,因为数字和汉字笔画在书写方面具有一定的相似性,可以借鉴。同时帮助您练顺运笔。2、要想设计好签名,就要

    2022年9月6日
    4
  • Map的有序性_有序的map集合有哪些

    Map的有序性_有序的map集合有哪些//使用LinkedHashMap代替无序的HashMap实现publicstaticvoidmain(String[]args){/***Constructsanemptyinsertion-ordered<tt>LinkedHashMap</tt>instance*withthedefaul…

    2022年9月23日
    0
  • python二级考试考生必看[通俗易懂]

    python二级考试考生必看[通俗易懂]考试环境:Windows7操作系统,Python3.5版本。已经预装idle开发环境(没有pycharm、spyder)涉及到考试中需要使用的库,无需考生安装,已经安装调试完毕,考试全程采用物理断网,

    2022年7月5日
    37

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号