前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >线程的notify方法_forkjoinpool默认线程数量

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

作者头像
全栈程序员站长
发布于 2022-10-04 13:30:17
发布于 2022-10-04 13:30:17
5320
举报

大家好,又见面了,我是你们的朋友全栈君。

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

本章内容要解决的问题

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

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

(图1-1)

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

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

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

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

(图1-2)

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

(图1-3)

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

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

(图1-4)

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

​​​​​​​

(图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参数不可修改(除非直接更改源码打包)

(图1-6)

(图1-7)

至此,notify方法结束。

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

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

先来看看notifyAll方法源码吧:

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

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

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

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

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

(图1-8)

至此,notifyall方法结束。

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

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

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

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

(图1-9)

(图1-10)

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

最后,附上整体示意图:

notify与policy挪动策略图

QMode策略唤醒示意图

最后的问题?

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

简单解释一下:

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

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

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

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

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

2.线程的其他方法?

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

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年9月8日 上,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java的wait()、notify()学习三部曲之一:JVM源码分析
综述 Java的wait()、notify()学习三部曲由三篇文章组成,内容分别是: 一、通过阅读openjdk8的源码,分析和理解wait,notify在JVM中的具体执行过程; 二、修改J
程序员欣宸
2018/01/04
1.4K0
Java的wait()、notify()学习三部曲之一:JVM源码分析
Java锁与线程的那些事
“操作系统的线程状态和java的线程状态有什么关系?”这是校招时被问到的一个问题。当时只顾着看博文、面经等零散的资料,没有形成系统的知识体系,一时语塞,答的不是很对。在网上也没找到足够细致的讲解博文,于是整理出了这篇内容。
有赞coder
2021/07/20
5700
那些去请求锁的线程怎么样了?
不知道你有没有想过,那些去申请锁的线程都怎样了?有些可能申请到了锁,马上就能执行业务代码。但是如果有一个锁被很多个线程需要,那么这些线程是如何被处理的呢?
Java架构师必看
2021/11/01
2610
干货 | 深入分析Object.wait/notify实现机制
作者简介 占军,就职携程地面业务部,负责地面搜索服务开发。Java爱好者,知识分享工作者。 最简单的东西,往往包含了最复杂的实现,因为需要为上层的存在提供一个稳定的基础,Object作为java中所有
携程技术
2018/03/16
2.3K0
干货 | 深入分析Object.wait/notify实现机制
面试官都叫好的Synchronized底层实现,这工资开多少一个月?
本系列文章将对HotSpot的synchronized锁实现进行全面分析,内容包括偏向锁、轻量级锁、重量级锁的加锁、解锁、锁升级流程的原理及源码分析,希望给在研究synchronized路上的同学一些帮助。
李红
2019/08/08
6790
多线程基础(七):关于HotSpot中notify方法不具备随机性的证明
在前面关于wait/notify及notifyAll方法的时候,notify在源码的注释中说到notify选择唤醒的线程是任意的,但是依赖于具体实现的jvm。原文如下:
冬天里的懒猫
2020/09/10
4740
话说 wait、notify 、 notifyAll
说起java的线程之间的通信,难免会想起它,他就是 wait 、notify、notifyAll
木子的昼夜
2021/03/04
1K0
话说 wait、notify 、 notifyAll
Java的wait()、notify()学习三部曲之三:修改JVM源码控制抢锁顺序
程序员欣宸
2018/01/04
7830
Java的wait()、notify()学习三部曲之三:修改JVM源码控制抢锁顺序
Monitor(管程/监视器)详解
  Monitor,直译为“监视器”,而操作系统领域一般翻译为“管程”。管程是指管理共享变量以及对共享变量操作的过程,让它们支持并发。在Java 1.5之前,Java语言提供的唯一并发语言就是管程,Java 1.5之后提供的SDK并发包也是以管程为基础的。除了Java之外,C/C++、C#等高级语言也都是支持管程的。synchronized关键字和wait()、notify()、notifyAll()这三个方法是Java中实现管程技术的组成部分。
忧愁的chafry
2022/10/30
1.8K0
Monitor(管程/监视器)详解
Java的wait()、notify()学习三部曲之二:修改JVM源码看参数
程序员欣宸
2018/01/04
1.2K0
Java的wait()、notify()学习三部曲之二:修改JVM源码看参数
Java的wait和notify学习三部曲之二:修改JVM源码看参数
编译JVM源码需要搭建编译环境,推荐使用docker,因为我已准备好了一个完善的编译环境镜像,详情请参照《
程序员欣宸
2020/05/26
3840
大神讲解的计算机底层原理
• 程序次序规则:同一个线程内,按照代码出现的顺序,前面的代码先行于后面的代码,准确的说是控制流顺序,因为要考虑到分支和循环结构。
入门笔记
2022/06/03
3570
大神讲解的计算机底层原理
浅谈synchronized与Object.wait/notify原理
synchronized是Java中常用的锁机制,synchronized+Object.wait/notify是常用的等待唤醒机制,那它们的实现原理是什么呢?本文就synchronized与Object.wait/notify为例谈谈以下内容。
luoxn28
2021/04/08
7090
Synchronized 的一个点,面试官可能都记错了。
而关于 Synchronized 我去年还专门翻阅 JVM HotSpot 1.8 的源码来研究了一波,那时候我就发现有一个点,一个几乎网上所有文章包括《Java并发编程的艺术》也是这样说的一个点。
why技术
2021/04/02
4530
监视器
想了解 synchronized 是如何运行的?就要先搞清楚 synchronized 是如何实现? synchronized 同步锁是通过 JVM 内置的 Monitor 监视器实现的,而监视器又是依赖操作系统的互斥锁 Mutex 实现的,那接下来我们先来了解一下监视器。
磊哥
2022/05/10
9070
监视器
基础篇:详解锁原理,volatile+cas、synchronized的底层实现
字节码出现了4: monitorenter和14: monitorexit两个指令;字面理解就是监视进入,监视退出。可以理解为代码块执行前的加锁,和退出同步时的解锁
潜行前行
2020/12/11
1.3K0
基础篇:详解锁原理,volatile+cas、synchronized的底层实现
【并发编程】2 synchronized底层实现原理、Java内存模型JMM;monitor、CAS、乐观锁和悲观锁;对象的内存结构、Mark Word、锁升级
本文为5、6小节,1~4节请查阅【并发编程】1 synchronized底层实现原理、Java内存模型JMM;monitor、CAS、乐观锁和悲观锁;对象的内存结构、Mark Word、锁升级
寻求出路的程序媛
2024/05/13
1370
【并发编程】2 synchronized底层实现原理、Java内存模型JMM;monitor、CAS、乐观锁和悲观锁;对象的内存结构、Mark Word、锁升级
如何阅读JVM 源码
JDK中JVM(安装在本地C:\Program Files\Java\jdk1.8.0_121\jre\bin\server下jvm.dll)本身并不开源,只能找来openJDK来看(说是和JDK相似度很高)
王小明_HIT
2020/06/16
2.1K0
吊打Java面试官-Java锁升级详解
JDK早期,synchronized 叫做重量级锁,因为申请锁资源必须通过kernel,系统调用
JavaEdge
2020/05/27
3K1
吊打Java面试官-Java锁升级详解
synchronized锁详解
    如:两个线程对初始值为 0 的静态变量一个做自增,一个做自减,各做 5000 次,结果是 0 吗?(针对这个问题进行分析)
忧愁的chafry
2022/10/30
5990
synchronized锁详解
推荐阅读
相关推荐
Java的wait()、notify()学习三部曲之一:JVM源码分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档