java并发编程02——JMM

本文从Java内存模型角度分析了内存可见性、happens-before关系及重排序概念,阐述了Volatile关键字的内存语义及其实现机制,强调其在多线程环境下的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 线程通信和线程同步             

        并发编程的两个核心问题是线程通信和线程同步,其中线程通信指线程之间以何种机制交换信息。常见的通信机制有两种:共享内存(线程之间共享公共状态,通过读-写公共状态来隐式通信)、消息传递(线程之间通过发送信息来显示通信),java采用共享内存的通行机制。同步指控制不同线程之间操作发生相对顺序(互斥)的机制。本篇主要从java的内存模型角度分析java底层如何保证内存可见性从而确保线程之间能够正常通行。

 java 内存模型(JMM)         

        java线程之间的通讯由JMM控制,JMM决定一个线程对共享变量的写入何时对其他线程可见。

 happens-before关系             

     定义:如果A 操作happends-before B操作,那么A操作的结果将对B操作可见。

    判断方法

            1、 一个线程中的每个操作 happens-before 于该线程中的任意后续操作。

            2、对一个监视器的解锁 happens-before 于随后对该监视器(同一个锁)的加锁。

            3、对一个监视器的解锁 happens-before 于随后对该监视器(同一个锁)的加锁。

            4、如果A happens-before B 且 B happends-before C ,那么Ahappens-before C。

 重排序                                          

       重排序分编译器重排序和处理器重排序,编译器重排序是指编译器在不改变单线程程序语义的情况下,可以改变语句的执行顺序,达到优化的目的。处理器重排序是指如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序,达到指令并行执行的目的。  

       重排序引发多线程的内存可见性问题,JMM会禁止特定类型的编译器重排序,同时在java编译器在生成的指令序列的适当位置插入内存屏障以此来禁止特定类型的处理器从排序。           

 顺序一致性内存模型对比JMM

       顺序一致性模型是一个理想的参考模型,提供了极强的内存可见性保证,JMM参考这个模型。

       在顺序一致性模型中,一个线程中的所有操作必须按照程序的流程来执行,不管同步与否,所有线程只能看到一个单一的操作执行顺序,JMM中无此保证,JMM对于同步程序有顺序一致性的效果,未同步程序在JMM中不但整体的执行顺序是无序的,而且所有线程看到的操作顺序也可能不一致,例如:线程A 执行 a=10操作(将值写到本地缓存),在将其刷新到主存之前,此操作只对线程A可见,在其他线程看来,因为看不到a的新值,所以就以为线程A并没有执行此操作。JMM对未同步的程序只提供最小安全性,线程执行时读取的值要么是某个线程写入的值,要么是默认值(0,null,false),不会出现一些无中生有的值。

        顺序一致性模型保证对所有的内存读/写都具有原子性。JMM不保证对64位的long 、double变量的读/写操作具有原子性。从jsr-133内存模型开始(jdk5),仅仅只允许把一个64位long/double型变量的写操作拆分成两个32位的写操作来执行,任意的读操作在jsr-133中都具有原子性。

 volatile                                         

        volatile具有可见性,对一个volatile变量的读,总是能看到对这个volatile变量最后的写入。同时volaile具有原子性,对任意单个volatile变量的读/写具有原子性(对long、double类型很有意义,对v++这种复合操作不具原子性)。

        volatile 的写-读与锁的释放-获取有相同的内存效果(写==释放锁 ,读==获取锁)。

        volatile 读/写的内存语义:当写一个volatile变量时,JMM会把对应的本地内存中的共享变量刷新到主存,实际是向接下来将要读取这个变量的某个线程发出消息。当读一个voltaile变量时,JMM会把该线程对应的本地缓存置为无效,线程接下来将从主存中读取共享变量。实际是接收到了之前某个线程发出的消息。因此volatile读/写实际是两个线程之间通过主存进行通信。

       为了实现volatile的内存语义,JMM针对编译器制定了以下3条重排序规则,同时为了实现规则,JMM采取了如图1所示的内存屏障插入策略。

               1、当第二个操作是volatile写时,不管第一个操作(volatile操作,普通操作)是什么,都不能重排序。

               2、当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。

               3、当第一个操作是volatile写,第二个操作是volatile读时,不能重排序。

            图1

 final域                                        

       对于final域,编译器和处理器遵守两条重排序规则:1、在构造函数内对一个final域的写入与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作不能重排序。2、初次读一个包含final域的对象的引用与随后初次读这个final域,这两个操作之间不能重排序。JMM禁止把final域的写重排序到构造函数之外,由此可保证在对象引用为任意线程可见之前,对象final域已经被正确初始化了(普通域不具有这个保障),当然前提条件是final引用不能从构造函数内“溢出”(对象未构造完成之前就将其引用暴露出去)。编译器会在final域写之后,构造函数返回之前插入StoreStore屏障,由此便确保了final域的写不会重排序到构造函数之外。通过为final域增加读/写重排序规则,可以为java程序员提供初始化安全保证:只要对象是正确初始化的(被构造对象的引用在s构造函数中没“溢出”),那么不需要同步就可以保证任意线程都能看到final域在构造函数中被初始化的值。

 

 

内容概要:本文深入解析了扣子COZE AI编程及其详细应用代码案例,旨在帮助读者理解新一代低门槛智能体开发范式。文章从五个维度展开:关键概念、核心技巧、典型应用场景、详细代码案例分析以及未来发展趋势。首先介绍了扣子COZE的核心概念,如Bot、Workflow、Plugin、Memory和Knowledge。接着分享了意图识别、函数调用链、动态Prompt、渐进式发布及监控可观测等核心技巧。然后列举了企业内部智能客服、电商导购助手、教育领域AI助教和金融行业合规质检等应用场景。最后,通过构建“会议纪要智能助手”的详细代码案例,展示了从需求描述、技术方案、Workflow节点拆解到调试与上线的全过程,并展望了多智能体协作、本地私有部署、Agent2Agent协议、边缘计算插件和实RAG等未来发展方向。; 适合人群:对AI编程感兴趣的开发者,尤其是希望快速落地AI产品的技术人员。; 使用场景及目标:①学习如何使用扣子COZE构建生产级智能体;②掌握智能体实例、自动化流程、扩展能力和知识库的使用方法;③通过实际案例理解如何实现会议纪要智能助手的功能,包括触发器设置、下载节点、LLM节点Prompt设计、Code节点处理和邮件节点配置。; 阅读建议:本文不仅提供了理论知识,还包含了详细的代码案例,建议读者结合实际业务需求进行实践,逐步掌握扣子COZE的各项功能,并关注其未来的发展趋势。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值