Java内存模型(JMM)与多线程编程实战

article/2025/6/19 21:45:13

最近正在复习Java八股,所以会将一些热门的八股问题,结合ai与自身理解写成博客便于记忆
在这里插入图片描述
今天将以这四个问题为依据。

一、JMM内存模型解析

1. JMM核心概念

Java内存模型(Java Memory Model)定义了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量的底层细节。

三大核心问题:
  • 原子性:一个操作或多个操作要么全部执行成功,要么全部不执行
  • 可见性:当一个线程修改了共享变量的值,其他线程能够立即看到修改后的值
  • 有序性:程序执行的顺序按照代码的先后顺序执行(允许指令重排序优化)

2. JMM内存结构

[线程工作内存] ←→ [主内存](私有)          (共享)
  • 工作内存:每个线程私有的内存空间
  • 主内存:所有线程共享的内存区域

二、JMM如何保证三大特性

1. 原子性保障

实现机制

  • 基本类型访问(除long/double)具有原子性
  • synchronized块(monitorenter/monitorexit)
  • Lock接口的实现类
  • Atomic原子类(CAS操作)

示例

private AtomicInteger count = new AtomicInteger(0);public void increment() {count.incrementAndGet(); // CAS原子操作
}

2. 可见性保障

实现机制

  • volatile关键字(禁止缓存,直接读写主内存)
  • synchronized(解锁前写回主内存,加锁时清空工作内存)
  • final(正确初始化后不可变)

volatile示例

private volatile boolean flag = false;public void setFlag() {flag = true; // 修改立即对其他线程可见
}

3. 有序性保障

实现机制

  • volatile(禁止指令重排序)
  • synchronized(同一时刻只有一个线程执行)
  • happens-before原则(编译器/处理器必须遵守的规则)

happens-before规则

  1. 程序顺序规则
  2. 锁规则
  3. volatile规则
  4. 传递性规则
  5. 线程启动/终止规则

三、多线程交替打印0-100

1. synchronized实现

public class AlternatePrint {private static int num = 0;private static final Object lock = new Object();public static void main(String[] args) {new Thread(() -> {while (num <= 100) {synchronized (lock) {if (num % 2 == 0) {System.out.println(Thread.currentThread().getName() + ": " + num++);lock.notify();} else {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}, "EvenThread").start();new Thread(() -> {while (num <= 100) {synchronized (lock) {if (num % 2 != 0) {System.out.println(Thread.currentThread().getName() + ": " + num++);lock.notify();} else {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}, "OddThread").start();}
}

2. ReentrantLock实现

public class AlternatePrintWithLock {private static int num = 0;private static final ReentrantLock lock = new ReentrantLock();private static final Condition condition = lock.newCondition();public static void main(String[] args) {Thread evenThread = new Thread(() -> {while (num <= 100) {lock.lock();try {if (num % 2 == 0) {System.out.println(Thread.currentThread().getName() + ": " + num++);condition.signal();} else {condition.await();}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}, "EvenThread");Thread oddThread = new Thread(() -> {while (num <= 100) {lock.lock();try {if (num % 2 != 0) {System.out.println(Thread.currentThread().getName() + ": " + num++);condition.signal();} else {condition.await();}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}, "OddThread");evenThread.start();oddThread.start();}
}

四、多线程交替打印ABC

1. 精准控制版本(三个线程)

public class AlternatePrintABC {private static final ReentrantLock lock = new ReentrantLock();private static final Condition conditionA = lock.newCondition();private static final Condition conditionB = lock.newCondition();private static final Condition conditionC = lock.newCondition();private static volatile int state = 0;public static void main(String[] args) {new Thread(() -> {for (int i = 0; i < 10; ) {lock.lock();try {while (state % 3 != 0) {conditionA.await();}System.out.print("A");state++;i++;conditionB.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}, "Thread-A").start();new Thread(() -> {for (int i = 0; i < 10; ) {lock.lock();try {while (state % 3 != 1) {conditionB.await();}System.out.print("B");state++;i++;conditionC.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}, "Thread-B").start();new Thread(() -> {for (int i = 0; i < 10; ) {lock.lock();try {while (state % 3 != 2) {conditionC.await();}System.out.print("C");state++;i++;conditionA.signal();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}, "Thread-C").start();}
}

2. 简化版本(使用单个Condition)

public class AlternatePrintABCSimple {private static final Object lock = new Object();private static volatile int state = 0;public static void main(String[] args) {new Thread(() -> {synchronized (lock) {for (int i = 0; i < 10; i++) {while (state % 3 != 0) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.print("A");state++;lock.notifyAll();}}}, "Thread-A").start();new Thread(() -> {synchronized (lock) {for (int i = 0; i < 10; i++) {while (state % 3 != 1) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.print("B");state++;lock.notifyAll();}}}, "Thread-B").start();new Thread(() -> {synchronized (lock) {for (int i = 0; i < 10; i++) {while (state % 3 != 2) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.print("C");state++;lock.notifyAll();}}}, "Thread-C").start();}
}

五、关键知识点总结

1. JMM要点

  • 原子性:关注操作是否被中断
  • 可见性:关注修改是否及时可见
  • 有序性:关注执行顺序是否符合预期

2. 线程通信要点

  • wait/notify:必须在同步块中使用
  • Condition:可创建多个等待队列
  • volatile:适合单一状态标志

3. 交替打印模式

  • 状态变量:控制打印顺序
  • 精确唤醒:Condition优于notifyAll
  • 循环检查:防止虚假唤醒

六、扩展思考

1. 如何实现N个线程交替打印?

解决方案

  1. 使用state % N判断当前应打印的线程
  2. 每个线程对应一个Condition
  3. 链式唤醒(A→B→C→…→N→A)

2. 如何避免死锁?

检查清单

  • 避免嵌套锁
  • 使用tryLock设置超时
  • 统一获取锁的顺序
  • 使用jstack分析死锁

http://www.hkcw.cn/article/NZPwtKXQcu.shtml

相关文章

Spring Cache核心原理与快速入门指南

文章目录 前言一、Spring Cache核心原理1.1 架构设计思想1.2 运行时执行流程1.3 核心组件协作1.4 关键机制详解1.5 扩展点设计1.6 与Spring事务的协同 二、快速入门实战三、局限性3.1 多级缓存一致性缺陷3.2 分布式锁能力缺失3.3 事务集成陷阱 总结 前言 在当今高并发、低延迟…

【设计模式-4.5】行为型——迭代器模式

说明&#xff1a;本文介绍设计模式中&#xff0c;行为型设计模式之一的迭代器模式。 定义 迭代器模式&#xff08;Iterator Pattern&#xff09;&#xff0c;也叫作游标模式&#xff08;Cursor Pattern&#xff09;&#xff0c;它提供一种按顺序访问集合/容器对象元素的方法&…

【Python训练营打卡】day40 @浙大疏锦行

DAY 40 训练和测试的规范写法 知识点回顾&#xff1a; 1. 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中 2. 展平操作&#xff1a;除第一个维度batchsize外全部展平 3. dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropo…

软件技术如何赚钱

1. 开发并销售软件产品​ ​ 独立应用开发&#xff1a;针对特定需求或市场痛点&#xff0c;开发移动应用、桌面软件或网页应用。例如&#xff0c;开发一款专注于时间管理的移动应用&#xff0c;帮助用户提高工作效率。以 Python 结合 Kivy 框架开发一个简单的待办事项应用为例…

【Github/Gitee Webhook触发自动部署-Jenkins】

Github/Gitee Webhook触发自动部署-Jenkins #mermaid-svg-ryhZQMOzmkQZNMwX {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ryhZQMOzmkQZNMwX .error-icon{fill:#552222;}#mermaid-svg-ryhZQMOzmkQZNMwX .error-tex…

华为OD机试真题——最小的调整次数/特异性双端队列(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《最小的调整次数/特异性双端…

建筑兔零基础人工智能自学记录101|Transformer(1)-14

Transformer 谷歌提出&#xff0c;一组编码-解码器 可以同时处理&#xff0c;通过位置编码来处理单词 实质是token词语接龙&#xff08;只是有不同的概率&#xff09; token对应向量 Transformer简述 文生图就需要用到transformer黑箱 token 内部层次 中间主要是embedding…

网线水晶头接法与8根线芯作用解析

网线的正确接法至关重要&#xff0c;它直接影响网络的稳定性与传输速度。而了解每根线的作用&#xff0c;更是深入掌握网络布线知识的关键。常见的网线为非屏蔽双绞线&#xff08;UTP&#xff09;&#xff0c;内部包含 8 根不同颜色的线芯&#xff0c;两两相互缠绕&#xff0c;…

【GESP真题解析】第 2 集 GESP 三级样题卷编程题 1:逛商场

大家好,我是莫小特。 这篇文章给大家分享 GESP 三级样题卷编程题第 1 题:逛商场。 题目链接 洛谷链接:B3848 逛商场 一、完成输入 根据输入格式描述,输入一共有三行,第一行为整数 N,数据范围: 1 ≤ N ≤ 100 1 \le N \le 100 1≤N≤100,使用 int 类型。 第二行为 N …

Nacos实战——动态 IP 黑名单过滤

1、需求分析 一些恶意用户&#xff08;‏可能是黑客、爬虫、DDoS ؜攻击者&#xff09;可能频繁请求服务器资​源&#xff0c;导致资源占用过高。针对这种问题&#xff0c;可以通过IP‏ 封禁&#xff0c;可以有效拉؜黑攻击者&#xff0c;防止资源​被滥用&#xff0c;保障合法…

基于Web的濒危野生动物保护信息管理系统设计(源码+定制+开发)濒危野生动物监测与保护平台开发 面向公众参与的野生动物保护与预警信息系统

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

流媒体协议分析:流媒体传输的基石

在流媒体传输过程中&#xff0c;协议的选择至关重要&#xff0c;它决定了数据如何封装、传输和解析&#xff0c;直接影响着视频的播放质量和用户体验。本文将深入分析几种常见的流媒体传输协议&#xff0c;探讨它们的特点、应用场景及优缺点。 协议分类概述 流媒体传输协议根据…

通过mqtt 发布温湿度

参考 用HAL库改写江科大的stm32入门例子-补充DHT11_江科大stm32安装hal库-CSDN博客 老夫上课的时候 &#xff0c;这部份讲的比较多 &#xff0c;出发点是 安利 “单总线”的具体使用。 这里无非是引入dht11 库&#xff0c; 使用前初始化 然后通话dht11库的方法 读取数据 &…

ApiHug 1.3.9 支持 Spring 3.5.0 + Plugin 0.7.4 内置小插件升级!儿童节快乐!!!

有用内置小插件 - ApiHug小插件&#xff0c;大用途https://apihug.github.io/zhCN-docs/how/005_helpful_inner_plugin SDK: [1.3.9-RELEASE] - 2025-06-01 Move the router auto-processing to an internal plugin for enhanced flexibility.Translate the OAS to json sch…

CTFHub-RCE 命令注入-无过滤

观察源代码 判断是Windows还是Linux 源代码中有 ping -c 4 说明是Linux 查看有哪些文件 127.0.0.1|ls 发现除了index.php文件外&#xff0c;还存在一个可疑的文件 打开flag文件 我们尝试打开这个文件 127.0.0.1|cat 19492844826916.php 可是发现 文本内容显示不出来&…

Mysql库的操作和表的操作

Mysql库和表的操作 库的操作1.查看数据库列表2.创建数据库3.使用数据库4.查看当前在那个数据库中5.显示数据库的创建语句6.修改数据库7.删除数据库8.备份和恢复数据库9.查看数据的连接情况(简单来说就是查看有多少人使用你的数据库) 表的操作1.创建表2.查看表结构3.修改表本身(…

Excel如何分开查看工作表方便数据撰写

首先我这里有2class和3class两个工作表 接下来我们点击视图 按照顺序分别点击新建窗口和全部重排 ### 然后就是这样 接下来就OK了

C++23 已弃用特性

文章目录 1. std::aligned_storage 与 std::aligned_union1.1 特性介绍1.2 被弃用的原因1.3 替代方案 2. std::numeric_limits::has_denorm2.1 特性介绍2.2 被弃用的原因 3. 总结 C23 已弃用特性包括&#xff1a;std::aligned_storage、std::aligned_union 与 std::numeric_lim…

MySQL事务和索引原理

目录 1. MySQL事务原理 1.1. 事务的基本概念 1.2. 事务隔离的实现机制 1.3. 事务的启动方式 2. 索引的原理 2.1. 索引的作用 2.2. 索引常用模型及适用场景 2.3. InnoDB中的索引结构 2.4. 索引维护 2.5. 覆盖索引 2.6. 联合索引和最左缀原则 2.7. 索引下推 1. MySQL事…

第十一章 Java基础-继承

文章目录 1.继承来源2.继承特点3.子类能继承父类中哪些内容1.继承来源 是为了解决代码的重复冗余。