当前位置: 首页 > news >正文

Java多线程学习(五)

今天整理内存可见性相关知识点
你好!很高兴能帮你梳理 Java 多线程的核心知识点。写技术博客时,逻辑的层层递进非常重要。我们可以从“为什么需要同步”聊到“具体的实现工具”。

一、编译器优化与内存可见性

在单线程环境下,编译器和 CPU 会为了性能大开绿灯,进行指令重排序。但在多线程环境下,这往往是 Bug 的温床。

1. 什么是可见性问题?

在 Java 内存模型(JMM)中,每个线程都有自己的工作内存(Cache),而所有变量都存在主内存中。

  • 线程 A 修改了变量,可能只停留在自己的工作内存。
  • 线程 B 读取的还是旧的主内存数据。
2. 编译器优化(指令重排)

为了提高执行效率,编译器有时会调整代码逻辑顺序。例如:

// 原始代码inta=1;booleanflag=true;// 编译器可能优化为booleanflag=true;inta=1;

在多线程下,如果flag代表a已经准备好了,这种重排就会导致另一个线程读到还没初始化的a


二、 轻量级同步锁:volatile关键字

volatile是 Java 提供的最轻量的同步机制。它主要有两个核心作用:

  1. 保证可见性:一旦一个变量被声明为volatile,任何线程对它的修改都会立即刷新回主内存,其他线程读取时也会直接从主内存获取。
  2. 禁止指令重排序:通过在代码中插入“内存屏障”,确保volatile变量前后的操作不会乱序。

注意volatile不保证原子性(比如i++操作)。如果需要原子性,还是得靠synchronizedAtomic类。


三、 线程间的“对讲机”:wait()notify()

这两个方法是Object类的方法,用于实现线程间的协作。

  • wait():让当前线程进入等待状态,并释放它持有的锁
  • notify():随机唤醒一个在该对象上等待的线程。
  • notifyAll():唤醒所有等待线程(通常更推荐,更安全)。

核心原则:它们必须在synchronized代码块内使用,否则会抛出IllegalMonitorStateException


四、 终极对决:wait()vssleep()

这是面试中的高频题,我们可以通过下表一目了然:

特性Object.wait()Thread.sleep()
所属类来自Object来自Thread
锁的处理会释放锁,允许其他线程进入不释放锁,抱着锁睡觉
使用前提必须在同步块synchronized可以在任何地方使用
唤醒条件需要notify()唤醒或时间到时间到自动唤醒
用途线程间通信/协作暂停执行/模拟耗时

五、 实战代码示例:生产者消费者模型

publicclassSharedData{privateintdata;privatebooleanavailable=false;// 消费者调用publicsynchronizedvoidconsume()throwsInterruptedException{while(!available){wait();// 没数据,释放锁,等着}System.out.println("消费数据: "+data);available=false;notifyAll();// 通知生产者}// 生产者调用publicsynchronizedvoidproduce(intvalue)throwsInterruptedException{while(available){wait();// 有数据还没被消费,等着}data=value;available=true;System.out.println("生产数据: "+data);notifyAll();// 通知消费者}}

💡 结语

理解 Java 多线程的关键在于理解内存模型锁的机制volatile解决了“看得到”的问题,而synchronizedwait/notify解决了“排队与协作”的问题。

http://www.jsqmd.com/news/519979/

相关文章:

  • AutoGen Studio效果展示:Qwen3-4B-Instruct-2507驱动的自动化法律合同审查Agent案例
  • 前端学习之HTML5+CSS3基础
  • 嵌入式OBDII CAN驱动库:物理层接入与多帧解析实战
  • 手把手教你用R-Studio Technician搭建个人数据恢复工作站(附硬件清单与避坑指南)
  • 多分类任务中SHAP特征重要性可视化:从summary_plot报错到实战调优
  • 嵌入式OTA升级失败率下降83%的关键:用C语言实现可验证状态机(含完整FSM状态迁移图与超时自愈逻辑)
  • cv_resnet18_ocr-detection ONNX导出实战:跨平台部署,C++/Java都能用
  • K8S 控制器-资源调度-叩丁狼
  • 魔搭社区实战:零代码玩转Qwen2.5-3B-Instruct-GGUF云端部署
  • 告别C#,我用Python+PyCharm+AutoCAD搞定了CAD二次开发(附完整代码)
  • GLM-OCR多模态识别模型:从零开始快速部署与测试
  • MuMu模拟器+Edge浏览器:H5页面元素定位的实战指南
  • 终极指南:如何用StardewXnbHack一键解锁《星露谷物语》所有游戏资源
  • FeRAM嵌入式驱动库:轻量、实时、线程安全的铁电存储控制方案
  • Qwen3-0.6B-FP8企业应用:法律合同初稿生成+关键条款提示双模协同案例
  • 第五章 渲染管线
  • 液驱剪叉电气系统拆解:从ECU到线束的保姆级指南(附LGMG AS1212实例)
  • Alpamayo-R1-10B作品集:10组高难度长尾场景(鬼探头、视线遮挡、异形车辆)应对案例
  • OpenClaw多终端控制:通过飞书管理GLM-4.7-Flash任务实践
  • 别再乱接AGND和DGND了!手把手教你搞定数模混合电路的地平面设计(附PCB布局实例)
  • MogFace人脸检测模型-WebUI作品:100%覆盖侧脸/低头/遮挡/运动模糊的挑战样本集
  • 嵌入式轻量级参数存储:带校验码与Code ID的EEPROM偏好管理
  • 告别微信QQ!用群晖NAS+Vocechat搭建你的私人聊天室(附Cpolar内网穿透教程)
  • AI Studio上传大文件太慢?教你用Python脚本批量解压zip文件(附完整代码)
  • 用robomimic玩转机器人模仿学习:从数据采集到策略部署全流程解析(2024最新版)
  • 论快速排序的时间复杂度
  • DAMOYOLO-S模型Linux生产环境部署:Ubuntu 20.04系统配置
  • MY9221 12通道LED驱动芯片原理与STM32嵌入式实践
  • CasRel开源镜像免配置部署:Argo Workflows编排多阶段知识图谱构建流水线
  • Citra模拟器:跨平台3DS游戏体验方案让玩家突破硬件限制