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

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

最近正在复习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.xdnf.cn/news/10448.html

相关文章:

  • 【小米拥抱AI】小米开源 MiMo-7B-RL-0530
  • 湖北理元理律师事务所:用科学规划重塑债务人生
  • 什么是 TOML?
  • NHANES指标推荐:ALI
  • <4>, Qt窗口
  • mysql慢sql的实际处理方案之一
  • MySQL事务和索引原理
  • WIN32-内存管理
  • leetcode hot100刷题日记——32.杨辉三角
  • Leetcode 3231. 要删除的递增子序列的最小数量
  • Docker-搭建MySQL主从复制与双主双从
  • 解常微分方程组
  • 代码随想录算法训练营第60期第五十三天打卡
  • C57-断言函数assert
  • 【Dv3Admin】工具请求配置文件解析
  • 【PCI】PCI入门介绍(包含部分PCIe讲解)
  • [USACO1.5] 八皇后 Checker Challenge Java
  • 智慧物流园区整体解决方案
  • LeeCode 98. 验证二叉搜索树
  • C#数字金额转中文大写金额:代码解析
  • CppCon 2014 学习:Pragmatic Type Erasure
  • vue-09(使用自定义事件和作用域插槽构建可重用组件)
  • Hbase
  • 如何真正实现软件开发“快”起来:破除误区与落地实践
  • 通义灵码深度实战测评:从零构建智能家居控制中枢,体验AI编程新范式
  • 新版智慧景区信息化系统解决方案
  • JOIN 与子查询的性能对比分析
  • 【shell】通过Shell命令占用内存
  • 【代码坏味道】膨胀类 Bloaters
  • 力扣热题100之翻转二叉树