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工程师的必经之路。

目录
相关文章
|
4月前
|
存储 算法 Java
Java的垃圾回收算法演进:从Serial到ZGC
Java的自动内存管理(垃圾回收,GC)是其区别于C++的重要特性之一。
417 3
|
API 数据库 开发者
Python微服务框架:Flask与FastAPI的融合创新
在当今高度互联的世界中,构建可扩展、灵活和高效的微服务架构变得至关重要。Python作为一种广泛应用于Web开发的编程语言,其微服务框架Flask和FastAPI的概念与实践日益受到关注。本文将介绍这两个框架的核心概念,并探讨它们在实际应用中的强大功能和优势。
|
3月前
|
人工智能 前端开发 JavaScript
用AI重塑RPA稳定性:实在Agent TARS语义定位技术拆解与落地实践
实在智能在实在Agent v7.3.4中推出TARS AI元素定位技术,通过视觉-语义联合建模,实现多模态编码、语义锚点生成与动态匹配优化,显著提升RPA在敏捷前端环境下的元素识别稳定性与自适应能力,配置即用,助力企业自动化迈向真正无人值守。(239字)
|
3月前
|
人工智能 编解码 Java
Harness Engineering:耗时一周,我是如何将应用的AI Coding率提升至90%的
文章内容基于作者个人技术实践与独立思考,旨在分享经验,仅代表个人观点。
1275 7
|
3月前
|
人工智能 文字识别 运维
文档智能处理与ReAct推理链:RAG系统的两个"隐形引擎"
本文深入解析RAG系统中两大“隐形引擎”:文档智能处理(含多格式解析、语义分片、QA抽取)与ReAct推理链(支持多轮思考-行动-观察)。二者协同提升知识库质量与AI推理能力,是决定RAG效果的关键底层能力。
|
4月前
|
监控 供应链 BI
Quick BI使用案例19:交叉表中当日订单金额百分位与基于嵌套计算的订单金额日环比百分位的双重分析
本文详解生鲜电商如何用“订单金额按列百分位”以及“基于嵌套计算的订单金额日环比百分位”的双重分析实现区域需求实时监控:连续2天百分位超80%为“爆发区”自动补货,连续2天百分位低于10%为“冰冻区”智能调拨,降低损耗、提升现货率。
|
4月前
使用经验模态分解(EMD)处理振动信号,并结合样本熵进行特征提取
使用经验模态分解(EMD)处理振动信号,并结合样本熵进行特征提取
483 3
|
4月前
|
人工智能 弹性计算 监控
我是怎么用 29 块钱让 AI Agent 7×24 在线帮我干活的
AI Agent部署踩坑后发现:选对方式比选对模型更重要!本地跑易OOM、全托管难定制,阿里云OpenClaw轻量自托管方案成最优解——2核4G服务器预装镜像,零代码开机即用,支持企微/飞书等多通道,新用户首月仅29元。
|
4月前
|
数据采集 人工智能 自然语言处理
解码罗兰艺境GEO“1+11”解决方案全景图:从技术原理到商业增长
本文系统阐述罗兰艺境GEO解决方案的“1+11”全栈技术体系(1项发明专利+11项软件著作权),对应七大层级、十二项核心资产,从顶层专利、理论框架、智能中台、语义基建、商业产品、网站应用到安全基座,逐层解析每一模块如何协同为客户构建可继承、可验证的AI语义资产库,最终实现从技术原理到商业增长的确定性路径。
278 3
|
2月前
|
人工智能 测试技术 API
【阿里云官方】容器模式布设OpenClaw轻量化构建思路
阿里云官方推出的OpenClaw智能助理,基于通义千问大模型,提供六大核心场景支持:超级助理、内容创作、股票分析、一人团队、开发助手与海外运营。零代码3分钟快速部署,安全可靠、开箱即用,助力开发者、创作者及运营者提效降本、加速业务增长。(239字)