java并发编程四 Monitor 概念,api介绍与线程状态转换

news2024/9/22 4:19:55

Monitor 概念

Java 对象头 以 32 位虚拟机为例子:
普通对象
在这里插入图片描述

数组对象
在这里插入图片描述

其中 Mark Word 结构为
在这里插入图片描述

64 位虚拟机 Mark Word
在这里插入图片描述

小故事
故事角色

  • 老王 - JVM
  • 小南 - 线程
  • 小女 - 线程
  • 房间 - 对象
  • 房间门上 - 防盗锁 - Monitor
  • 房间门上 - 小南书包 - 轻量级锁
  • 房间门上 - 刻上小南大名 - 偏向锁
  • 批量重刻名 - 一个类的偏向锁撤销到达 20 阈值
  • 不能刻名字 - 批量撤销该类对象的偏向锁,设置该类不可偏向

小南要使用房间保证计算不被其它人干扰(原子性),最初,他用的是防盗锁,当上下文切换时,锁住门。这样,即使他离开了,别人也进不了门,他的工作就是安全的。

但是,很多情况下没人跟他来竞争房间的使用权。小女是要用房间,但使用的时间上是错开的,小南白天用,小女晚上用。每次上锁太麻烦了,有没有更简单的办法呢?

小南和小女商量了一下,约定不锁门了,而是谁用房间,谁把自己的书包挂在门口,但他们的书包样式都一样,因此每次进门前得翻翻书包,看课本是谁的,如果是自己的,那么就可以进门,这样省的上锁解锁了。万一书包不是自己的,那么就在门外等,并通知对方下次用锁门的方式。

后来,小女回老家了,很长一段时间都不会用这个房间。小南每次还是挂书包,翻书包,虽然比锁门省事了,但仍然觉得麻烦。
于是,小南干脆在门上刻上了自己的名字:【小南专属房间,其它人勿用】,下次来用房间时,只要名字还在,那么说明没人打扰,还是可以安全地使用房间。如果这期间有其它人要用这个房间,那么由使用者将小南刻的名字擦掉,升级为挂书包的方式。

同学们都放假回老家了,小南就膨胀了,在 20 个房间刻上了自己的名字,想进哪个进哪个。后来他自己放假回老家了,这时小女回来了(她也要用这些房间),结果就是得一个个地擦掉小南刻的名字,升级为挂书包的方式。老王觉得这成本有点高,提出了一种批量重刻名的方法,他让小女不用挂书包了,可以直接在门上刻上自己的名字

后来,刻名的现象越来越频繁,老王受不了了:算了,这些房间都不能刻名了,只能挂书包

wait notify

小故事 - 为什么需要 wait

  • 由于条件不满足,小南不能继续进行计算

  • 但小南如果一直占用着锁,其它人就得一直阻塞,效率太低
    在这里插入图片描述

  • 于是老王单开了一间休息室(调用 wait 方法),让小南到休息室(WaitSet)等着去了,但这时锁释放开,
    其它人可以由老王随机安排进屋

  • 直到小M将烟送来,大叫一声 [ 你的烟到了 ] (调用 notify 方法)
    在这里插入图片描述

小南于是可以离开休息室,重新进入竞争锁的队列
在这里插入图片描述

API 介绍

  • obj.wait() 让进入 object 监视器的线程到 waitSet 等待
  • obj.notify() 在 object 上正在 waitSet 等待的线程中挑一个唤醒
  • obj.notifyAll() 让 object 上正在 waitSet 等待的线程全部唤醒

它们都是线程之间进行协作的手段,都属于 Object 对象的方法。必须获得此对象的锁,才能调用这几个方法

final static Object obj = new Object();
 public static void main(String[] args) {
 new Thread(() -> {
 synchronized (obj) {
 log.debug("执行....");
 try {
 obj.wait(); // 让线程在obj上一直等待下去
            } 
catch (InterruptedException e) {
 e.printStackTrace();
            }
 log.debug("其它代码....");
        }
    }).start();
 new Thread(() -> {
 synchronized (obj) {
 log.debug("执行....");
 try {
 obj.wait(); // 让线程在obj上一直等待下去
            } 
catch (InterruptedException e) {
 e.printStackTrace();
            }
 log.debug("其它代码....");
        }
    }).start();
     // 主线程两秒后执行
sleep(2);
 log.debug("唤醒 obj 上其它线程");
 synchronized (obj) {
 obj.notify(); // 唤醒obj上一个线程
// obj.notifyAll(); // 唤醒obj上所有等待线程
    }
 }

notify 的一种结果:

20:00:53.096 [Thread-0] c.TestWaitNotify - 执行.... 
20:00:53.099 [Thread-1] c.TestWaitNotify - 执行.... 
20:00:55.096 [main] c.TestWaitNotify - 唤醒 obj 上其它线程 
20:00:55.096 [Thread-0] c.TestWaitNotify - 其它代码....

notifyAll 的结果

19:58:15.457 [Thread-0] c.TestWaitNotify - 执行.... 
19:58:15.460 [Thread-1] c.TestWaitNotify - 执行.... 
19:58:17.456 [main] c.TestWaitNotify - 唤醒 obj 上其它线程 
19:58:17.456 [Thread-1] c.TestWaitNotify - 其它代码.... 
19:58:17.456 [Thread-0] c.TestWaitNotify - 其它代码....

wait() 方法会释放对象的锁,进入 WaitSet 等待区,从而让其他线程就机会获取对象的锁。无限制等待,直到notify 为止
wait(long n) 有时限的等待, 到 n 毫秒后结束等待,或是被 notify

提示
sleep(long n) 和 wait(long n) 的区别

  1. sleep 是 Thread 方法,而 wait 是 Object 的方法
  2. sleep 不需要强制和 synchronized 配合使用,但 wait 需要和 synchronized 一起用
  3. sleep 在睡眠的同时,不会释放对象锁的,但 wait 在等待的时候会释放对象锁
  4. 它们状态 TIMED_WAITING

Park & Unpark

基本使用
它们是 LockSupport 类中的方法

// 暂停当前线程
LockSupport.park(); 
// 恢复某个线程的运行
LockSupport.unpark(暂停线程对象)

先 park 再 unpark

Thread t1 = new Thread(() -> {
 log.debug("start...");
 sleep(1);
 log.debug("park...");
 LockSupport.park();
 log.debug("resume...");
 },"t1");
 t1.start();
 sleep(2);
 log.debug("unpark...");
 LockSupport.unpark(t1);

输出

18:42:52.585 c.TestParkUnpark [t1] - start... 
18:42:53.589 c.TestParkUnpark [t1] - park... 
18:42:54.583 c.TestParkUnpark [main] - unpark... 
18:42:54.583 c.TestParkUnpark [t1] - resume... 

特点
与 Object 的 wait & notify 相比

  • wait,notify 和 notifyAll 必须配合 Object Monitor 一起使用,而 park,unpark 不必
  • park & unpark 是以线程为单位来【阻塞】和【唤醒】线程,而 notify 只能随机唤醒一个等待线程,notifyAll 是唤醒所有等待线程,就不那么【精确】
  • park & unpark 可以先 unpark,而 wait & notify 不能先 notify

重新理解线程状态转换

在这里插入图片描述

假设有线程 Thread t
情况 1 NEW --> RUNNABLE
当调用 t.start() 方法时,由 NEW --> RUNNABLE
情况 2 RUNNABLE <–> WAITING
t 线程用 synchronized(obj) 获取了对象锁后

  • 调用 obj.wait() 方法时,t 线程从 调用RUNNABLE --> WAITING
  • obj.notify() ,obj.notifyAll() ,t.interrupt() 时
    • 竞争锁成功,t 线程从 WAITING --> RUNNABLE
    • 竞争锁失败,t 线程从WAITING --> BLOCKED
public class TestWaitNotify {
 final static Object obj = new Object();
 public static void main(String[] args) {
    new Thread(() -> {
 synchronized (obj) {
 log.debug("执行....");
 try {
 obj.wait();
                } 
catch (InterruptedException e) {
 e.printStackTrace();
                }
 log.debug("其它代码...."); // 断点
            }
        },"t1").start();
 new Thread(() -> {
 synchronized (obj) {
 log.debug("执行....");
 try {
 obj.wait();
                } 
catch (InterruptedException e) {
 e.printStackTrace();
                }
 log.debug("其它代码...."); // 断点
            }
        },"t2").start();
 sleep(0.5);
 log.debug("唤醒 obj 上其它线程");
 synchronized (obj) {
 obj.notifyAll(); // 唤醒obj上所有等待线程  断点
        }
    }
 }

情况 3 RUNNABLE <–> WAITING

  • 当前线程调用 t.join() 方法时,当前线程从 RUNNABLE --> WAITING
    • 注意是当前线程在t 线程对象的监视器上等待
    • t 线程运行结束,或调用了当前线程的 interrupt() 时,当前线程从 WAITING --> RUNNABLE

情况 4 RUNNABLE <–> WAITING

  • 当前线程调用 LockSupport.park() 方法会让当前线程从RUNNABLE --> WAITING
  • 调用LockSupport.unpark(目标线程) 或调用了线程 的 interrupt() ,会让目标线程从
    WAITING --> RUNNABLE

情况 5 RUNNABLE <–> TIMED_WAITING

  • t 线程用 synchronized(obj) 获取了对象锁后
    • 调用 obj.wait(long n) 方法时,t 线程从 RUNNABLE --> TIMED_WAITING
    • t 线程等待时间超过了 n 毫秒,或调用 obj.notify() ,obj.notifyAll() ,
      • 争锁成功,t 线程从
      • TIMED_WAITING --> RUNNABLE
      • 竞争锁失败,t 线程从 TIMED_WAITING --> BLOCKED

情况 6 RUNNABLE <–> TIMED_WAITING

  • 当前线程调用 t.interrupt() 时t.join(long n) 方法时,当前线程从 RUNNABLE --> TIMED_WAITING
    • 注意是当前线程在t 线程对象的监视器上等待
  • 当前线程等待时间超过了 n 毫秒,或t 线程运行结束,或调用了当前线程的 interrupt() 时,当前线程从TIMED_WAITING --> RUNNABLE

情况 7 RUNNABLE <–> TIMED_WAITING

  • 当前线程调用Thread.sleep(long n) ,当前线程从 RUNNABLE --> TIMED_WAITING
  • 当前线程等待时间超过了 n 毫秒,当前线程从TIMED_WAITING --> RUNNABLE
    情况 8 RUNNABLE <–> TIMED_WAITING
  • 当前线程调用 LockSupport.parkNanos(long nanos) 或 程从 RUNNABLE --> IMED_WAITING
  • 调用 LockSupport.parkUntil(long millis) 时,当前线LockSupport.unpark(目标线程) 或调用了线程 的 interrupt() ,或是等待超时,会让目标线程从 TIMED_WAITING–> RUNNABLE

情况 9 RUNNABLE <–> BLOCKED

  • t 线程用 synchronized(obj) 获取了对象锁时如果竞争失败,从 RUNNABLE --> BLOCKED
  • 持 obj 锁线程的同步代码块执行完毕,会唤醒该对象上所有 BLOCKED 的线程重新竞争,如果其中 t 线程竞争成功,从 BLOCKED --> RUNNABLE ,其它失败的线程仍然 BLOCKED
    情况 10 RUNNABLE <–> TERMINATED
    当前线程所有代码运行完毕,进入TERMINATED

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1325448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Elasticsearch常见面试题

文章目录 1.简单介绍下ES&#xff1f;2.简单介绍当前可以下载的ES稳定版本&#xff1f;3.安装ES前需要安装哪种软件&#xff1f;4.请介绍启动ES服务的步骤&#xff1f;5.ES中的倒排索引是什么&#xff1f;6. ES是如何实现master选举的&#xff1f;7. 如何解决ES集群的脑裂问题8…

本地文件内容搜索神器AnyTXT Searcher如何搭建与远程访问

文章目录 前言1. AnyTXT Searcher1.1 下载安装AnyTXT Searcher 2. 下载安装注册cpolar3. AnyTXT Searcher设置和操作3.1 AnyTXT结合cpolar—公网访问搜索神器3.2 公网访问测试 4. 固定连接公网地址 前言 你是否遇到过这种情况&#xff0c;异地办公或者不在公司&#xff0c;想找…

ubuntu qt 源码编译

官方源码下载地址 : 源码地址 选择要下载的版本 dmg结尾的是MacOS系统里使用的Qt库&#xff0c;qt-everywhere-opensource-src-4.7.0是Qt源码包&#xff0c;有zip和tar.gz两个压缩格式的&#xff0c;两个内容是一样的&#xff0c;只是zip一般在Windows下比较流行&#xff0c;…

【100个Cocos实例】快要圣诞节了,给大家支个招!

引言 Mask遮罩组件的一些简单实例 在游戏开发中常常需要在UI界面上展示玩家的头像或者Logo&#xff0c;通常都会是正方形。 偶尔也会有一些奇形怪状的需求&#xff0c;例如五边形、六边形、心形等等。 本文将介绍一下在Cocos游戏开发中Mask遮罩组件的一些简单实例&#xff…

九州未来向开放原子开源基金会捐赠OpenV2X,共建繁荣开源生态

12月16日&#xff0c;以“一切为了开发者”为主题的开放原子开发者大会在无锡成功举办。会上&#xff0c;九州未来将OpenV2X车路协同开源项目正式捐赠给开放原子开源基金会&#xff0c;并签署项目捐赠协议&#xff0c;通过开源共创的方式&#xff0c;携手开源伙伴共同打造车路协…

[微服务 ]微服务集成中的3个常见缺陷,以及如何避免它们

微服务风靡一时。他们有一个有趣的价值主张&#xff0c;即在与多个软件开发团队共同开发的同时&#xff0c;将软件快速推向市场。因此&#xff0c;微服务是在扩展您的开发力量的同时保持高敏捷性和快速的开发速度。 简而言之&#xff0c;您将系统分解为微服务。分解并不是什么新…

RLAIF方法与传说中的函数‘Q‘,揭露OpenAI那不为人知的Qstar计划

早晨刚起来,看群里新哥转了这个帖子: 帖子不长,但是基本是爆炸类的新闻了!这个应该也就是Sam之前被董事会诟病的所谓隐瞒了的真相! 在讲解这个帖子之前,先要普及2个概念: 1- RLAIF: 不是TGIF,虽然今天确实是周五 RLAIF是Google今年9月新出来的论文,论文…

智能优化算法应用:基于堆优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于堆优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于堆优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.堆优化算法4.实验参数设定5.算法结果6.参考文…

tcpdump抓包技巧

1. 常见的抓包工具 1.1 tcpdump 是Linux下常用的抓包工具&#xff0c;它是一个命令行工具&#xff0c;可以抓取和Wireshark类似的数据&#xff0c;而且保存的数据包&#xff0c;可以放到Wireshark中分析。如果你的Linux服务器需要抓包分析问题&#xff0c;它是一个非常好的选择…

算法基础之约数之和

约数之和 核心思想&#xff1a; #include<iostream>#include<algorithm>#include<vector>#include<unordered_map>using namespace std;typedef long long LL;const int N 110 , mod 1e97;int main(){int n;cin>>n;unordered_map<int,int&…

使用opencv实现图像中几何图形检测

1 几何图形检测介绍 1.1 轮廓(contours) 什么是轮廓&#xff0c;简单说轮廓就是一些列点相连组成形状、它们拥有同样的颜色、轮廓发现在图像的对象分析、对象检测等方面是非常有用的工具&#xff0c;在OpenCV 中使用轮廓发现相关函数时候要求输入图像是二值图像&#xff0c;这…

Python学习笔记(六):函数的多返回值、函数的多种参数使用形式、匿名函数、文件的读取操作、文件的写入 、文件的追加

目录 一、函数的多返回值 二、函数的多种参数使用形式 2.1位置参数 2.2关键字参数 2.3缺省参数 2.4不定长参数 三、匿名函数 3.1 函数作为参数传递 3.2 函数的定义 3.3 匿名函数定义语法&#xff1a; 四、文件的读取操作 4.1 open&#xff08;&#xff09;打开函数…

【WPF.NET开发】样式和模板

本文内容 示例样式ControlTemplateDataTemplate触发器视觉状态共享资源和主题 Windows Presentation Foundation (WPF) 样式设置和模板化是指一套功能&#xff0c;这套功能使开发者和设计者能够为其产品创建极具视觉表现力的效果和一致的外观。 自定义应用的外观时&#xff0…

【精选】Lombok概述及常用注解使用方法

Lombok概述 Lombok项目是一个java库&#xff0c;它可以自动插入到编辑器和构建工具中&#xff0c;增强java的性能。不需要再写getter、setter或equals方法&#xff0c;只要有一个注解&#xff0c;就有一个功能齐全的构建器、自动记录变量等等。 以前的Java项目中&#xff0c;充…

2002年AMC8数学竞赛中英文真题典型考题、考点分析和答案解析

今天是2023年12月21日&#xff0c;距离2024年的AMC8正式考试倒计时已不足30天了。 六分成长继续和您一起&#xff0c;从历年的真题中来了解考试题型、考试形式、对知识点查漏补缺。如果您有任何关于AMC8比赛的任何问题都可以问我&#xff0c;关于题目的解析也可以交流。敲黑板…

Ansible的脚本----playbook剧本

Playbook组成部分 tasks 任务&#xff1a;包含要在目标主机上执行的操作&#xff0c;使用模块定义这些操作。每个任务都是一个模块的调用。Variables 变量&#xff1a;存储和传递数据。变量可以自定义&#xff0c;可以在playbook当中定义全局变量&#xff0c;可以外部传参。T…

ARM GIC(二)中断分类

一、中断状态 对于每一个中断而言,有以下4个状态: inactive:中断处于无效状态 pending:中断处于有效状态,但是cpu没有响应该中断 active:cpu在响应该中断 active and pending:cpu在响应该中断,但是该中断源又发送中断过来 以下是中断状态的转移图。至于图中的转移…

基于Redis限流(aop切面+redis实现“令牌桶算法”)

令牌桶算法属于流量控制算法&#xff0c;在一定时间内保证一个键&#xff08;key&#xff09;的访问量不超过某个阈值。这里的关键是设置一个令牌桶&#xff0c;在某个时间段内生成一定数量的令牌&#xff0c;然后每次访问时从桶中获取令牌&#xff0c;如果桶中没有令牌&#x…

U-MixFormer:用于高效语义分割的类unet结构的混合注意力Transformer

论文&#xff1a; 代码&#xff1a;GitHub - RecklessRonan/MuSE 感觉这篇比较优雅无痛涨点欸.....最近要期末了没时间看文章和做实验了&#xff08;摊 摘要 语义分割在Transformer架构的适应下取得了显著的进步。与Transformer的进步并行的是基于CNN的U-Net在高质量医学影…

数据可视化---直方图

内容导航 类别内容导航机器学习机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归机器学习算法—聚类机器学习算法—异常检测机器学习算法—时间序列数据可视化数据可视化—折线图数据可视化—箱线图数据可视化—柱状图数据可视化—饼图、环形图、雷达图统…