JAVA synchronized关键字涉及的Monitor对象中 EntryList和WaitSet工作机制

在Java的synchronized同步机制中,Monitor对象的EntryList和WaitSet是两个关键队列,它们分别管理不同状态的线程。下面我将详细解释它们的工作原理,并提供代码示例说明。

EntryList(锁竞争队列)

作用机制

EntryList保存了所有等待获取锁的线程。当锁被某个线程持有时,其他尝试获取该锁的线程会被放入EntryList中,处于BLOCKED状态。

工作流程

  1. 线程尝试获取锁时发现锁已被持有
  2. 线程被放入EntryList等待
  3. 当持有锁的线程释放锁时,JVM会从EntryList中选择一个线程唤醒
  4. 被唤醒的线程尝试获取锁

代码示例

public class EntryListDemo {private static final Object lock = new Object();public static void main(String[] args) {// 线程1先获取锁new Thread(() -> {synchronized (lock) {System.out.println("线程1获取锁");try {Thread.sleep(3000); // 模拟长时间操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程1释放锁");}}).start();// 线程2稍后尝试获取锁new Thread(() -> {try {Thread.sleep(100); // 确保线程1先获取锁} catch (InterruptedException e) {e.printStackTrace();}synchronized (lock) { // 这里会被放入EntryList等待System.out.println("线程2获取锁");}}).start();}
}

输出结果

线程1获取锁
(等待约3秒)
线程1释放锁
线程2获取锁

WaitSet(等待队列)

作用机制

WaitSet保存了调用了wait()方法的线程。这些线程已经获得了锁,但主动释放锁并等待被唤醒。

工作流程

  1. 线程获得锁后调用wait()方法
  2. 线程释放锁并进入WaitSet,处于WAITING状态
  3. 其他线程调用notify()/notifyAll()时,线程从WaitSet转移到EntryList
  4. 当再次获得锁时,从wait()调用处继续执行

代码示例

public class WaitSetDemo {private static final Object lock = new Object();private static volatile boolean condition = false;public static void main(String[] args) throws InterruptedException {// 等待线程Thread waitingThread = new Thread(() -> {synchronized (lock) {System.out.println("等待线程获得锁");while (!condition) {try {System.out.println("等待线程调用wait()");lock.wait(); // 释放锁并进入WaitSetSystem.out.println("等待线程被唤醒");} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("等待线程完成工作");}});// 通知线程Thread notifyingThread = new Thread(() -> {synchronized (lock) {System.out.println("通知线程获得锁");condition = true;lock.notify(); // 唤醒WaitSet中的一个线程System.out.println("通知线程已发送通知");}});waitingThread.start();Thread.sleep(500); // 确保等待线程先执行notifyingThread.start();}
}

输出结果

等待线程获得锁
等待线程调用wait()
通知线程获得锁
通知线程已发送通知
等待线程被唤醒
等待线程完成工作

EntryList和WaitSet的区别

特性EntryListWaitSet
线程状态BLOCKEDWAITING
进入方式竞争锁失败自动进入主动调用wait()进入
唤醒方式锁释放时自动唤醒必须通过notify()/notifyAll()
锁的状态从未获得过锁曾获得锁但主动释放
转移目标获得锁后进入运行状态被唤醒后进入EntryList

完整生命周期示例

public class MonitorLifecycleDemo {private static final Object lock = new Object();public static void main(String[] args) {// 线程1:演示wait()和notify()new Thread(() -> {synchronized (lock) {System.out.println("线程1获得锁");try {System.out.println("线程1调用wait()进入WaitSet");lock.wait(); // 进入WaitSetSystem.out.println("线程1被唤醒,重新获得锁");} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程1释放锁");}}).start();// 线程2:竞争锁进入EntryListnew Thread(() -> {try {Thread.sleep(100); // 确保线程1先获得锁} catch (InterruptedException e) {e.printStackTrace();}synchronized (lock) {System.out.println("线程2从EntryList中被选中获得锁");System.out.println("线程2调用notify()唤醒WaitSet中的线程");lock.notify(); // 唤醒线程1,线程1进入EntryListtry {Thread.sleep(1000); // 保持锁一段时间} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程2释放锁");}}).start();// 线程3:展示EntryList中的竞争new Thread(() -> {try {Thread.sleep(200); // 确保线程2已获得锁} catch (InterruptedException e) {e.printStackTrace();}synchronized (lock) {System.out.println("线程3获得锁");}}).start();}
}

输出结果

线程1获得锁
线程1调用wait()进入WaitSet
线程2从EntryList中被选中获得锁
线程2调用notify()唤醒WaitSet中的线程
(等待约1秒)
线程2释放锁
线程1被唤醒,重新获得锁
线程1释放锁
线程3获得锁

这个示例展示了:

  1. 线程1获得锁后主动wait()进入WaitSet
  2. 线程2从EntryList中获得锁并notify()唤醒线程1
  3. 线程2释放锁后,线程1从WaitSet转移到EntryList并重新获得锁
  4. 最后线程3获得锁

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

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

相关文章

js-day10

JS学习之旅-day101. 作用域1.1 局部作用域1.2 全局作用域1.3 作用域链1.4 JS垃圾回收机制(GC)1.5 闭包1.6 变量提升2. 函数进阶2.1 函数提升2.2 函数参数2.3 箭头函数3. 解构赋值3.1 数组解构3.2 对象解构4. 数组遍历4.1 forEach4.2 filter1. 作用域 作…

智能数字式毫秒计在实际生活场景中的应用

在电力领域,SYN5307型数字毫秒表可精准监测特高压变电站断路器合闸时间差,定位继电保护装置信号延迟;工业自动化中,优化汽车焊装线时序、提升半导体晶圆切割良率;科研计量上,助力量子通信同步校准&#xff…

Java面试基础:概念

1. Java的特点跨平台性:Java的 “编写一次,运行无处不在” 是其最大的特点之一。Java编译器将源代码编译成字节码(bytecode),该字节码可以在任何安装了Java虚拟机(JVM)的系统上运行。面向对象:Java是一门严格的面向对象编程语言&a…

PyQt5高级窗口控件详解:停靠窗口、多文档界面与滚动条

掌握PyQt5的高级窗口控件,让你的GUI应用具备专业级的布局与交互体验 在PyQt5应用开发中,高效管理窗口布局和实现复杂交互功能是提升用户体验的关键。本文将深入解析三个核心高级控件:停靠窗口(QDockWidget)、多文档界面…

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | DrawingApp(画板组件)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— DrawingApp组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 的 Composition API&#xff08;<script setup>…

Eureka、Nacos、LoadBalance、OpenFeign​之间的区别联系和协作 (附代码讲解)

这篇文章聊聊微服务里的这几个老伙计&#xff1a;Eureka、Nacos、LoadBalance、OpenFeign。咱们做微服务开发&#xff0c;总会跟这几个组件打交道&#xff1a;Eureka、Nacos、Spring Cloud LoadBalancer、OpenFeign。它们各司其职又互相配合&#xff0c;今天就把它们的关系、用…

JavaSE-继承

继承&#xff08;inheritance&#xff09;继承的意义我们首先来看下面两个类&#xff1a;public class Dog {public String name;public int age;public void eat(){System.out.println(this.name"正在吃饭");}public void bark(){System.out.println(this.name"…

第二届虚拟现实、图像和信号处理国际学术会议(VRISP 2025)

重要信息 官网&#xff1a;www.icvisp.net 时间&#xff1a;2025年8月1-3日 地点&#xff1a;中国-长沙 简介 近年来&#xff0c;虚拟现实技术取得了显著进步&#xff0c;与5G、云计算和物联网等新一代信息技术的融合加速&#xff0c;推动了其在硬件、软件和内容应用等方面…

SpringBoot+Mybatis+MySQL+Vue+ElementUI前后端分离版:整体布局、架构调整(二)

目录 一、前言 二、后端调整 1.实体类调整 2.菜单相关接口 3.用户相关接口 4.新增工具类 5.新增菜单树返回类 6.配置类、拦截器 三、前端调整 1.请求调整 2.页面布局、样式调整 1.user.vue 2.index.vue 3.请求拦截 四、开发过程中的问题 五、附&#xff1a…

vue3官方文档学习心得

这几天抽空把vue3的文档整个看了一遍。简介 | Vue.js 23年写过一个vue2的项目&#xff0c;24年写了一个vue3的项目&#xff0c;页面功能比较简单&#xff0c;用几个简单的API&#xff0c;watch、watchEffect、ref、reactive就能实现的业务功能。 写了几年的react的&#xff0…

Pycharm恢复默认设置,配置导致复制粘贴等不能使用

在file 种找到manage IDE settings在manage IDE settings中找到restore default settings

【王树森推荐系统】召回12:曝光过滤 Bloom Filter

概述 曝光过滤通常是在召回阶段做&#xff0c;具体的方法就是用 Bloom Filter 曝光过滤问题 如果用户看过某个物品&#xff0c;则不再把该物品曝光给用户。原因是同一个物品重复曝光给用户会损害用户体验&#xff0c;但也不是所有推荐系统都有曝光过滤&#xff0c;像 youtube 这…

基于STM32单片机的心率血氧监测系统设计(STM32代码编写+手机APP设计+PCB设计+Proteus仿真)

系列文章目录 文章目录 系列文章目录前言1 资料获取与演示视频1.1 资料介绍1.2 资料获取1.3 演示视频 2 系统框架3 硬件3.1 主控制器3.2 显示屏3.3 WIFI模块3.4心率血氧传感器 4 设计PCB4.1 安装下载立创EDA专业版4.2 画原理图4.4 使用嘉立创下单助手进行下单&#xff0c;打板。…

main(int argc,char **agrv)的含义

今天和大家讨论一个常见的但是不容易深入了解的知识点。那就是 main 函数声明中使用到的 argc 和 argv 的含义。通常我们写主函数的时候一般都是直接使用int main() 或者 void main() 来声明 main 函数。但是你知道吗&#xff1f;在c89/c99的语言标准中&#xff0c;main函数的声…

如何简单实现发版不影响客户使用?nginx负载

nginx负载发版不影响客户使用 1.需要二台服务器 2.二台服务器均是正式环境配置 3.服务器Nginx配置修改 发版顺序&#xff1a;先在服务器2发版&#xff0c;发布成功后&#xff0c;再改服务器Nginx配置&#xff0c;重新加载nginx&#xff1b;然后在服务器再发版&#xff0c;发布成…

qt笔记(1)——Qtablewidget使用

1.基础使用方法 &#xff08;略&#xff09; 2.坑和注意点 2.1 设置一个单元格的编辑属性 在代码中&#xff0c;想要修改一个单元格的编辑属性&#xff0c;需要对这个item的flags进行设置&#xff1b;注意对一个tablewidget的一个item成员进行设置后&#xff0c;进行一次编…

字符串的模糊匹配方法介绍

字符串的模糊匹配方法介绍 目录字符串的模糊匹配方法介绍一、编辑距离&#xff08;Levenshtein Distance&#xff09;复杂度分析二、Jaro-Winkler 距离复杂度分析三、最长公共子序列&#xff08;LCS&#xff09;复杂度分析四、模糊搜索&#xff08;Fuzzy Search&#xff09;复杂…

ActiveMQ在Spring Boot中的详细使用指南

📋 目录 🚀 ActiveMQ简介 什么是ActiveMQ? 核心概念 🏗️ 基础架构组件 📝 重要概念解释 ActiveMQ vs 其他消息中间件 🔧 环境搭建 1. ActiveMQ服务端安装 Docker方式(推荐初学者) 手动安装方式 2. 验证安装 访问Web管理界面 连接参数 测试连接 �…

二元一次方程

前言 最近刚学二元一次方程&#xff0c;想写一篇专栏熟悉一下本文写给初一的同学看&#xff0c;学过的就划了吧二元一次方程 两个未知数最高项次数为 111 次为整式方程二元一次方程的解不唯一&#xff0c;但是二元一次方程可以用一个未知数来表达另一个未知数eg:eg:eg: xy1x y…

AI编程的未来是智能体原生开发?

目录 前言 一、从“串行”到“并行”&#xff1a;什么是智能体原生开发&#xff1f; 1.1 传统模式&#xff08;串行思维&#xff09; 1.2 智能体原生模式&#xff08;并行思维&#xff09; 二、程序员的新角色&#xff1a;从代码手艺人到系统思想家 三、软件开发的终局&a…