JMM——Java内存模型简介
JMM介绍JMM是基于CPU缓存模型实现的一套Java内存管理程序都在于解决多核情况下的缓存同步问题。它定义了主存和工作内存的抽象概念底层对应着CPU寄存器、高速缓存、RAM、CPU指令优化等。CPU缓存模型JMM特性可见性volatile可以保证不同线程对共享变量进行操作时的可见性。即当一个线程修改了共享变量时另一个线程可以读取到共享变量被修改后的值。有序性volatile会通过禁止指令重排序进而保证有序性。原子性对于单个的volatile修饰的变量的读写是可以保证原子性的但对于i这种复合操作并不能保证原子性。这句话的意思基本上就是说volatile不具备原子性了。【注】i属于非原子性操作是int tmp i;i tmp1;的简化这个流程分为了读-改-写一共三个原子性操作JMM特性的应用方式同时实现可见性、有序性、原子性需要使用synchronized,但是耗费性能同时实现可见性、有序性需要给共享变量加上volatile修饰符也就是适用于仅有一个线程修改其它线程读取的场景因为无原子性必须保证并发安全。【注】synchronized无法实现有序性所以需要volatile修饰符的加入同样的volatile修饰的变量如果想要具备原子性也需要锁机制的帮助例如synchronized或者Unsafecas指令例如AtomicInteger的实现单线程无需关心JMM特性原因是不会有其它线程操作数据不需要可见性和原子性无序性只是用于提升性能不会无脑影响语义多线程必须关心JMM特性原因是其它线程操作数据不可能用旧数据并且要保证数据的并发安全这需要可见性和原子性虽然指令重排提升了性能但会导致其它线程检测时机不准导致一些异常情况这需要禁止指令重排可见性volatile可见性实现原理【注】上图主存指的是所有线程共享的数据比如公共静态成员变量、公共成员变量而工作内存是线程自己私有的数据。如图所示别看加了一个volatile但是底层实现很繁杂首先要确保开启缓存一致性协议每个线程都要开启总线嗅探机制 会给主存的变量加锁然后基于以上步骤实现可见性如果存在资源的竞争这时需要加上锁来资源分配以保证线程资源安全有序性定义编码执行顺序可能会被编译器或者CPU进行指令重排序这原是一种高效执行策略但可以导致一些运行出现异常因此要禁止指令重排序。案例1DCLdouble check lockinginstance变量通过volatile的修饰获取了可见性和有序性代码如下。public class Singleton { private static volatile Singleton instance; public static Singleton getInstance() { if (instance null) { // 第一次检查 synchronized (Singleton.class) { if (instance null) { // 第二次检查 instance new Singleton(); // 创建对象 } } } return instance; } }没有volatile修饰instance new Singleton()执行指令分配内存在堆里给对象找块空地。赋值引用把内存地址赋给instance。初始化对象调用构造方法填充字段值。拥有volatile修饰instance new Singleton()执行指令分配内存在堆里给对象找块空地。初始化对象调用构造方法填充字段值。赋值引用把内存地址赋给instance。store作废其它线程的instance缓存并将instance回更到主存。案例2读写标志位通过添加volatile修饰符保证了可见性和有序性// 全局变量 int config 0; // 配置数据 boolean volatile ready false; // 初始化完成标志 // 线程 A (初始化线程) void init() { config 123; // 1. 写入配置数据 ready true; // 2. 标记初始化完成 } // 线程 B (使用线程) void use() { if (ready) { // 3. 检查标志 doSomething(config); // 4. 使用配置 } }可见性保证了写线程变更标志位后读线程可以立刻检测有序性保证了写线程按序执行不会导致必要的数据还未执行【注】如果案例1和案例2不是多线程而是单线程则无需担心可见性和有序性的问题原子性定义要么执行成功要么退回原样不会被其它线程所干扰不会发生上下文切换 或者 发生上下文切换但被同步锁保护分类1.指令层面的原子性天然具备单个指令往往具有原子性特征例如赋值、cas操作或者读取操作这类指令在执行当中不会发生上下文切换2.代码层面的原子性由多个指令组成的复杂指令例如i、new Object() 或者 一堆代码逻辑这类复杂指令在执行当中虽然会上下文切换但是可以用锁实现并发安全。【注】CPU指令集支持CAS操作而且是原子性CAS操作的硬件层面流程为锁住地址拒绝其它核心操作——数据校验——数据变更稍提一嘴硬件层面的阻塞是一种运行态下的等待这不同于内核态或者用户态的阻塞逻辑volatilevolatile并不保证原子性它仅用于实现共享数据的可见性和有序性
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2408535.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!