聊聊Java的内存模型

聊聊Java的内存模型

目录

1、Java的内存模型(JMM)介绍

JMM核心定义和作用

JVM和JMM的区别

2.JMM核心概念

主内存和工作内存

内存间的交互操作

内存三大特性

原子性

可见性

有序性

3.Happens-Before规则

Happens-Before规则介绍

六大happens-before规则

4.volatile关键字

5.JMM的常见误区

volatile无法保证原子性

指令重排序的陷阱


1、Java的内存模型(JMM)介绍

JMM核心定义和作用

Java内存模型(Java Memory Model,JMM)是Java虚拟机规范中定义的一种抽象概念,它规定了多线程环境下,线程如何与内存进行交互。

JMM的核心作用:

  • 定义程序中各个变量的访问规则
  • 确保多线程程序的可见性有序性原子性
  • 屏蔽不同硬件平台和操作系统的内存访问差异

JVM和JMM的区别

说到JMM,我们不得不提到它经常被人所搞混淆的另一个概念JVM,我们用一张表来直观表现出它们的区别。

JVM内存结构

Java内存模型
核心关注点数据存储的物理/逻辑分区线程与内存的交互规则
内容堆、栈、方法区等内存区域主内存、工作内存抽象概念
目的内存分配与管理多线程内存可见性控制


2.JMM核心概念

主内存和工作内存

  • 主内存:所有线程共享的内存区域,存储所有实例字段、静态字段和数组元素
  • 工作内存:每个线程私有的内存空间,存储线程使用变量的副本

当某个线程需要使用到内存中的变量时,他会先从主内存中复制一份该变量的副本到自己的工作内存当中,使用完后再将该变量写入主内存的共享内存中。

内存间的交互操作

  • lock/unlock:作用于主内存,标识变量为线程独占状态
  • read/load:从主内存读取变量到工作内存
  • use/assign:工作内存中使用和赋值操作
  • store/write:将工作内存变量写回主内存

内存三大特性

原子性

核心概念:原子性指一个操作或一系列操作要么全部执行成功,要么全部不执行,不会出现执行到一半的状态。

// 原子操作示例 int x = 10; // 原子的:一次性赋值 boolean flag = true; // 原子的 // 非原子操作示例 int i = 0; i++; // 非原子的,实际包含3个步骤: // 1.读取i的值到寄存器 // 2.寄存器值加1 // 3.写回内存 

可见性

核心概念:可见性指当一个线程修改了共享变量的值,其他线程能够立即看到修改后的值。

 private boolean running = true; // 主内存中的变量 public void run() { while (running) { // 工作内存中的副本 // 看不到running被改为false } } public void stop() { running = false; // 修改主内存,但工作内存可能没更新 }

有序性

核心概念:有序性指程序执行的顺序按照代码的先后顺序执行。但在多线程或优化环境下,指令可能被重排序

重排序原因:

  • 编译器优化重排序
  • 处理器指令级并行重排序
  • 内存系统重排序
 private int x = 0; private boolean flag = false; // 线程1执行 public void writer() { x = 42; // 1 flag = true; // 2 可能被重排到1之前! } // 线程2执行 public void reader() { if (flag) { // 3 System.out.println(x); // 可能输出0而不是42! } }

3.Happens-Before规则

Happens-Before规则介绍

Happens-Before是JMM的核心概念,它定义了两个操作之间的偏序关系

  • 如果操作A happens-before​ 操作B
  • 那么A的所有写操作对B的读操作都是可见

有点难看懂,我们用一个简单的例子就能快速理解

// 核心:happens-before ≠ 时间先后 int x = 0; int y = 0; // 时间上:先执行1,后执行2 x = 1; // 1 y = x + 1; // 2 // 逻辑上:1 happens-before 2 // 所以2一定能看到1写入的值

A happens-before B 翻译过来就是:A对B可见。

六大happens-before规则

  • 程序次序规则:线程内,按照程序代码顺序,前面的操作happens-before后面的操作。
  • 监视器锁规则:对一个锁的解锁操作happens-before后续对这个锁的加锁操作。
  • volatile变量规则:对一个volatile变量的操作happens-before后续对这个变量的操作。
  • 线程启动规则:Thread对象的start()方法调用happens-before该线程的每一个动作
  • 线程终止规则:线程中的所有操作happens-before其他线程检测到该线程已经终止
  • 传递性规则:如果A happens-before B,且B happens-before C,那么A happens-before C

4.volatile关键字

核心概述:volatile是一个重要的关键字,用于告知编译器某个变量的值可能会被程序外部的因素意外修改,从而避免编译器对该变量进行优化。它的主要作用是确保每次访问变量时都从内存中读取最新的值,而不是使用寄存器中的缓存值。

volatile提供了两大保证:

  • 可见性:修改立即对所有线程可见
  • 有序性:禁止指令重排序
 private volatile boolean flag = false; private int count = 0; public void writer() { count = 42; // 普通写操作 flag = true; // volatile写操作 } public void reader() { if (flag) { // volatile读操作 // 这里一定能看到count=42 System.out.println(count); } }

5.JMM的常见误区

volatile无法保证原子性

volatile可以保证可见性和有序性,但和synchronized不一样,不能保证原子性

// 错误:以为volatile能保证原子性 volatile int count = 0; count++; // 非原子操作 // 正确:使用原子类或同步 AtomicInteger atomicCount = new AtomicInteger(0); atomicCount.incrementAndGet();

指令重排序的陷阱

// 可能由于重排序导致问题 int a = 0; boolean flag = false; // 线程1 a = 1; // 1 flag = true; // 2 可能重排到1之前 // 线程2 if (flag) { System.out.println(a); // 可能输出0 }

此时我们需对flag使用volatile关键字修饰即可保证在a赋值后再执行flag=true操作。


制作不易,如果对你有帮助请点赞,评论,收藏,感谢大家的支持

Read more

从“敲代码”到“说需求”:AI到底如何改变应用开发?

前言 2023-2025 这短短 24 个月,生成式 AI 完成了从“一本正经地胡说八道”到“可信赖生产力”的跨越 。伴随幻觉率大幅下降、模型能力跃迁,以及向量数据库、AI 云原生、低代码等配套技术的成熟,应用开发方式正在发生一场“范式级”革命: * 开发单元从“代码文件”变成“模型能力”; * 开发者角色从“编码者”变成“需求描述者 + AI 训练师”; * 交付流程从“需求 → 设计 → 编码 → 测试 → 运维”变成“自然语言提示 → AI 生成 → 人工微调 → 一键部署”。 本文将从技术栈、工程流程、组织形态、商业模式四个维度,系统拆解这场变革的来龙去脉与未来走向。 技术栈迁移:从“

By Ne0inhk
AI 时代,为什么 “人人都是产品经理” 的时代才真正到来?

AI 时代,为什么 “人人都是产品经理” 的时代才真正到来?

从“口号”到“现实”:AI 如何重构产品经理的能力边界 传统“人人都是产品经理”的矛盾 “人人都是产品经理”的提法由来已久,但在传统产品开发模式中,这更像是一种理念倡导,而非可落地的实践,核心矛盾集中在三个维度: * 能力门槛高:产品经理需要同时掌握用户调研、需求分析、原型设计、跨部门协调等多维度技能,普通员工或用户难以系统掌握。 * 资源壁垒强:产品需求的落地需要依赖开发、设计、测试等团队的资源支持,非专业产品角色无法推动资源协调。 * 试错成本高:传统产品迭代周期以月为单位,需求验证成本极高,非专业人员的创意难以快速得到市场反馈。 这些矛盾导致“人人都是产品经理”始终停留在口号层面,真正能参与产品决策的依然是专业岗位人员。 AI 对产品能力的“平民化”重构 AI 技术的成熟,尤其是大语言模型(LLM)和生成式 AI的普及,正在从根本上打破传统产品开发的能力和资源壁垒,让非专业人员也能完成从创意到落地的全流程产品设计。以下是 AI 带来的核心改变: 1.

By Ne0inhk
10分钟零代码!用OpenClaw搭建私人微信AI助理,彻底解放双手

10分钟零代码!用OpenClaw搭建私人微信AI助理,彻底解放双手

做了这么久AI应用落地,我被问得最多的问题就是:“能不能给我的微信整个AI助理,自动回消息、管日程、汇总群聊?” 说实话,这个需求我自己折腾了快两年,踩过的坑能绕开三圈: * 最早用itchat、wechaty写Python脚本,代码写了几百行,调试了半个月,结果用了不到3天,微信直接限制登录,差点把主号搞封了; * 后来用企业微信机器人,只能在企业群里用,个人微信、私域群完全用不了,局限性拉满; * 再后来试了市面上的第三方SaaS工具,要么是按月付费贵得离谱,要么是所有聊天数据都要传到人家服务器,客户信息、私人聊天全泄露了,根本不敢用; * 最头疼的是,所有方案都要写代码、调接口、搭环境,新手根本无从下手,就算是开发者,也要折腾好几天才能跑通。 直到我把OpenClaw部署落地后,这个问题被彻底解决了。不用写一行代码,不用研究微信协议,不用申请任何企业资质,10分钟就能搭好一个完全私有化的微信AI助理,消息自动回复、群聊汇总、日程提醒、待办管理全搞定,而且数据全在本地,大模型可以接本地开源的,完全不用担心隐私泄露,封号风险也降到了最低。 这篇文章,我就用保姆级的步骤

By Ne0inhk

node-llama-cpp错误处理与调试:解决本地AI开发常见问题

node-llama-cpp错误处理与调试:解决本地AI开发常见问题 【免费下载链接】node-llama-cppRun AI models locally on your machine with node.js bindings for llama.cpp. Force a JSON schema on the model output on the generation level 项目地址: https://gitcode.com/gh_mirrors/no/node-llama-cpp node-llama-cpp是一款强大的工具,它提供了llama.cpp的node.js绑定,让你能够在本地机器上运行AI模型,并在生成级别强制模型输出JSON模式。对于新手和普通用户来说,在使用过程中可能会遇到各种错误和问题,本文将详细介绍常见错误的处理方法和调试技巧,帮助你顺利进行本地AI开发。 常见错误类型及解决方法 二进制文件未找到错误(NoBinaryFoundError)

By Ne0inhk