Java内存模型与并发编程的基石

简介: Java从诞生之初就内置了对多线程编程的支持,这使得Java在企业级后端开发中占据了统治地位。而这一切的基础正是Java内存模型(Java Memory Model,JMM)。

Java从诞生之初就内置了对多线程编程的支持,这使得Java在企业级后端开发中占据了统治地位。而这一切的基础正是Java内存模型(Java Memory Model,JMM)。JMM规范了多线程程序中,共享变量的访问规则以及线程间的通信行为,它解决了由于CPU缓存、编译器优化和指令重排序带来的可见性、原子性和有序性问题。本文将从硬件架构出发,深入讲解JMM的核心概念——happens-before原则、volatile语义、synchronized的内存效应,并结合实例分析常见并发陷阱。
参考:https://bgnno.cn/category/guide.html

现代多核处理器系统中,每个CPU核心都有自己的高速缓存(L1/L2/L3),主存(RAM)与CPU之间通过缓存一致性协议(如MESI)进行同步。在没有内存模型约束的情况下,编译器可能会对指令进行重排序以优化性能,CPU也可能会乱序执行。这导致在多线程环境下,一个线程对变量的修改可能对其他线程不可见,或者指令执行顺序出乎意料。Java内存模型正是为了屏蔽不同硬件平台的差异,为程序员提供一致的内存访问语义。

JMM的核心是定义了一组happens-before规则,用于判断两个操作之间是否存在顺序保证。如果A happens-before B,则A操作的结果对B操作可见,且A的执行顺序排在B之前。happens-before规则包括:
程序次序规则:在一个线程内,按照控制流顺序,书写在前面的操作happens-before后面的操作。
监视器锁规则:对一个锁的解锁操作happens-before后续对同一锁的加锁操作。
volatile变量规则:对一个volatile变量的写操作happens-before后续对该变量的读操作。
传递性:如果A happens-before B,且B happens-before C,则A happens-before C。
线程启动规则:线程的start()方法happens-before该线程内的任何动作。
线程终止规则:线程内的任何动作happens-before其他线程检测到该线程终止(如join()返回)。
中断规则:对线程的interrupt()调用happens-before被中断线程检测到中断。

理解happens-before是编写正确并发程序的关键。例如,以下代码片段可能产生死循环:

public class VisibilityDemo {
   
    private static boolean flag = true;
    public static void main(String[] args) throws InterruptedException {
   
        new Thread(() -> {
   
            while (flag) {
    }
            System.out.println("Thread exit");
        }).start();
        Thread.sleep(1000);
        flag = false; // 主线程修改flag
    }
}

由于没有同步机制,JVM可能将while(flag)优化为if(!flag) while(true),导致子线程永远看不到flag的更新。解决方案是将flag声明为volatile,这样写操作会立即刷新到主存,读操作每次都从主存读取,并且禁止重排序。
参考:https://rvxif.cn/category/puerh-tea.html

volatile的语义比synchronized更轻量,但不能保证复合操作的原子性(例如count++)。对于原子性需求,应使用java.util.concurrent.atomic包下的类,如AtomicInteger,或者使用synchronized块。synchronized不仅保证了互斥(同一时刻只有一个线程执行代码块),还保证了代码块内的变量修改对后续加锁线程可见。这是因为在释放锁之前,线程会将本地缓存写回主存;获取锁时,会使本地缓存失效,重新从主存读取。

JMM还规定了final域的内存语义:在构造函数内对一个final域的写入,与随后将该对象引用赋值给另一个引用变量之间,存在happens-before关系。这保证了正确构造的对象中,final域的值对所有线程都是可见的,无需额外同步。

更深层次上,JMM允许编译器在不改变单线程语义的前提下进行重排序,但必须遵循as-if-serial语义。对于多线程程序,开发者依赖happens-before规则来确保正确性。Java并发库中的java.util.concurrent类都是基于JMM构建的,例如ReentrantLock使用了AbstractQueuedSynchronizer,其内部利用了volatile变量和CAS操作。

常见并发问题包括:
数据竞争:多个线程同时访问同一变量,至少有一个是写操作,且没有使用happens-before来排序,导致不可预测的结果。
失效数据:线程读取到过期的变量值,通常由于缺乏可见性保证。
指令重排序导致的诡异问题:例如双重检查锁(Double-Checked Locking)在Java 5之前是有问题的,因为对象的初始化可能重排序导致其他线程看到未完全构造的对象。Java 5之后引入volatile解决了该问题。
参考:https://xrzqr.cn/

为了编写可靠的并发代码,应遵循以下原则:
尽量使用高层并发工具:Executors、ConcurrentHashMap、BlockingQueue等,避免直接操作synchronized和volatile。
不可变对象是最简单的共享方式:声明类为final,所有字段为final,不提供修改方法。
线程封闭:使用ThreadLocal将变量限制在线程内部,避免共享。
正确使用volatile:只用于简单的状态标志,且不依赖其复合操作。
理解发布与逸出:不要在构造函数中将this引用暴露给其他线程,否则可能造成未完全构造对象的逸出。

总之,Java内存模型是Java并发编程的基石,它定义了一套规范,使开发者能够编写出跨平台的线程安全代码。深入理解happens-before、volatile、synchronized的内存效应,是成为高级Java工程师的必经之路。

目录
相关文章
|
2月前
|
存储 算法 Java
Java的垃圾回收算法演进:从Serial到ZGC
Java的自动内存管理(垃圾回收,GC)是其区别于C++的重要特性之一。
278 3
|
3月前
|
Rust 中间件 API
BustAPI:当 Python 遇上 Rust,Web 框架也能“起飞“
BustAPI 是融合 Python 易用性与 Rust 高性能的 Web 框架:基于 PyO3 封装 Actix-Web,保留 Flask 风格语法,请求性能提升 10–50 倍;支持自动文档、类型校验、异步、中间件等生产级功能,迁移零成本,部署极简——让 Python 服务轻松应对高并发。
425 5
|
1月前
|
人工智能 前端开发 JavaScript
用AI重塑RPA稳定性:实在Agent TARS语义定位技术拆解与落地实践
实在智能在实在Agent v7.3.4中推出TARS AI元素定位技术,通过视觉-语义联合建模,实现多模态编码、语义锚点生成与动态匹配优化,显著提升RPA在敏捷前端环境下的元素识别稳定性与自适应能力,配置即用,助力企业自动化迈向真正无人值守。(239字)
|
1月前
|
人工智能 编解码 Java
Harness Engineering:耗时一周,我是如何将应用的AI Coding率提升至90%的
文章内容基于作者个人技术实践与独立思考,旨在分享经验,仅代表个人观点。
|
1月前
|
人工智能 文字识别 运维
文档智能处理与ReAct推理链:RAG系统的两个"隐形引擎"
本文深入解析RAG系统中两大“隐形引擎”:文档智能处理(含多格式解析、语义分片、QA抽取)与ReAct推理链(支持多轮思考-行动-观察)。二者协同提升知识库质量与AI推理能力,是决定RAG效果的关键底层能力。
|
2月前
|
监控 供应链 BI
Quick BI使用案例19:交叉表中当日订单金额百分位与基于嵌套计算的订单金额日环比百分位的双重分析
本文详解生鲜电商如何用“订单金额按列百分位”以及“基于嵌套计算的订单金额日环比百分位”的双重分析实现区域需求实时监控:连续2天百分位超80%为“爆发区”自动补货,连续2天百分位低于10%为“冰冻区”智能调拨,降低损耗、提升现货率。
|
8天前
|
运维 开发者
同样标注为 Claude,为何效果差异明显:中转链路模型一致性排查实录
同样标注为 Claude,为什么线上效果会出现明显差异?本文基于一次真实排查,给出“总览体检—来源下钻—隔离对照—复检恢复”的工程化方法,重点解决中转链路中的模型一致性与路由漂移问题。适合正在做大模型应用稳定性治理、可观测性建设与故障复盘的团队参考。
128 2
同样标注为 Claude,为何效果差异明显:中转链路模型一致性排查实录
|
8天前
|
canal 关系型数据库 MySQL
MySQL LIKE查询太慢?手把手搭建Elasticsearch站内搜索
本文详解MySQL模糊搜索性能瓶颈及Elasticsearch全文检索解决方案:剖析`LIKE '%关键词%'`全表扫描原理,对比MySQL全文索引局限,深入讲解倒排索引机制,并实战演示Logstash/Canal数据同步、IK中文分词、高亮搜索等核心环节,助你构建毫秒级站内搜索。(239字)
|
2月前
|
数据采集 人工智能 自然语言处理
解码罗兰艺境GEO“1+11”解决方案全景图:从技术原理到商业增长
本文系统阐述罗兰艺境GEO解决方案的“1+11”全栈技术体系(1项发明专利+11项软件著作权),对应七大层级、十二项核心资产,从顶层专利、理论框架、智能中台、语义基建、商业产品、网站应用到安全基座,逐层解析每一模块如何协同为客户构建可继承、可验证的AI语义资产库,最终实现从技术原理到商业增长的确定性路径。
216 3
|
8天前
|
人工智能 安全 数据安全/隐私保护
企业引入 AI 智能体,不能只管采购报销,更要管权限、行为和审计
金融机构引入 AI 智能体,不能只停留在采购账号和费用报销层面。AI 一旦进入业务场景,就会接触数据、流程、工具和员工判断。 今天分享一下金融企业应如何围绕权限、行为和审计建立 AI 管控体系,并介绍 FinClaw 如何通过管理后台统一查看用户对话、数字员工记忆、工具调用、Token 用量和执行日志,让 AI 真正实现可管、可控、可追溯。
104 3

热门文章

最新文章