Java内存模型理解

3.1java内存模型的基础:

介绍基本概念
在这里插入图片描述

  1. 并发编程的两个问题
    通信和线程同步
    通信是指线程之间以何种机制来交互信息:两种方式 共享内存 和 消息传递
    1.共享内存的模型里,线程间通过共享程序的公共状态进行隐式通信
    2.消息传递的模型里,线程通过发送消息进行通信
    同步是指程序中用于控制不同线程操作发生顺序的机制
    1.共享内存的模型里,同步间通过显示进行的,程序要显示指定某个方法或代码互斥执行
    2.消息传递的模型里,消息发生必须要在消息接收前,同步是隐式进行的
    java并发采用的是共享内存模型
  2. java内存模型的抽象结构
    实例域,静态域,和数组元素(共享变量)都存储在堆内存中,线程共享
    每个线程都有一个本地内存,本地内存中存储了该线程读写共享变量的副本,本地内存是JMM的抽象概念,并不真实存在,它涵盖了缓存,写缓冲区,寄存器以及其他硬件和编译器优化。
    JMM通过控制主内存与每个线程的本地内存之间的交互,来为java程序员提供内存可见性保证
  3. 从源代码到指令序列的重排序
    执行程序时,为了提高性能,编译器和处理器会对指令进行重排序,分为3中类型
    1.编译器优化的重排序,编译器在不改变单线程语义的前提下,重排
    2.指令级并行的重排序,处理器对机器指令的执行顺序
    3.内存系统的重排序,处理器使用缓存和读写缓冲区,使得加载和存储操作看上去可能是乱序执行的
    对于编译器的重排序规则1,JMM会禁止,对于处理器重排序,JMM会生成指令序列,插入内存屏障禁止重排序
    4.并发编程模型的分类
  4. happens-before原则
    在JMM中,如果一个操作的结果需要对另一个操作可见,那么两个操作必须要存在happens-before关系
    程序顺序规则:一个线程的每一个操作先于另一线程的任意操作
    监视器锁规则:对于一个锁的解锁,先于对这个锁的加锁
    volatile变量规则:对一个volatile域的写先于对这个域的读
    传递性:a先于b b先于c 则 a先于c

3.2 重排序

数据依赖性
as-if-serial语义
程序顺序规则

3.3 顺序一致性

是一个理想参考模型,在设计时,处理器的存储模型和编译语言的内存模型都会参照

  1. 数据竞争与顺序一致性
    当程序未正确同步时,就可能会存在数据竞争,java中的定义:一个线程写,一个线程读,写和读没有通过同步来排序
    这里的同步是广义的同步,包括常用的同步源语synchronized volatile final
  2. 顺序一致性的内存模型
    计算机科学家理想化的一个模型,给程序员提供了强内存可见性保证,两大特征
    线程的所有操作必须按照程序的顺序执行
    所有线程都只能看到一个单一的操作执行顺序,每个操作都必须是原子操作且对所有线程可见
  3. 同步程序的顺序一致性效果
    使用个锁来实现,在JMM中,临界区内的代码可重排序,JMM会在退出和进入临界区时做处理,使得线程具有顺序一致性

3.4 volatile的内存语义

  1. volatile特性 禁止指令重排,内存可见性 原子性(对于单个读写操作)
  2. 写-读建立的happens-before关系
    volatile对线程的内存可见性的影响需要关注,volatile变量可以实现线程间通信,volatile的写和锁的释放有相同的语义,读和锁的获取有相同的语义
    在这里插入图片描述
  3. volatile的读写的内存语义
    当写一个volatile变量时,JMM会把本地变量刷新到主内存,当读一个volatile变量时,JMM会把线程对应的本地内存置为无效,从主内存中重新读取。
    1).线程A在写一个volatile变量,实质是线程向接下来要读这个变量的线程发送一个消息
    2).线程B读volatile变量,实质是接收到之前的某个线程发出的消息(在写volatile变量之前对共享变量的修改)
    3).线程A写volatile变量,线程B读volatile变量,这个过程实质是线程A通过主内存想线程B发送消息
  4. 内存语义的实现
    为了实现volatile的内存语义,编译器使用内存屏障来禁止处理器重排序,JMM内存屏障插入策略
    在volatile的写操作前面加StoreStore屏障
    在volatile的写操作后面加StoreLoad屏障
    在volatile的读操作前面加LoadLoad屏障
    在volatile的读操作后面加LoadStore屏障

3.5 锁的内存语义

  1. 锁的释放获取建立的happens-before关系
    锁是重要的同步机制, 锁可以让临界区互斥执行外,还可以让释放锁的线程向获取锁的线程发送消息
    在图中,线程A释放锁后,随后线程B获取同一个锁,在图总 2happens-before5,因此线程A释放锁之前所有可见的共享变量,在线程B获取同一个锁之后将立刻变得对线程B可见
  2. 锁释放和获取的内存语义
    释放锁时,会把共享变量刷新到主内存中,当线程获取锁时,JMM会把线程对应的本地内存置为无效,从而使得被监视器保护的临界区代码必须从主内存中读取共享变量
    1).线程A释放锁,实质是线程A向接下来将要获取锁的某个线程发出消息(线程A对变量的修改)
    2).线程B获取锁,实质是线程B接收之前A线程发出的消息
    3).线程A释放锁,线程B获取锁,这个过程实质是线程A通过主内存向线B发送消息
    在这里插入图片描述
  3. 内存语义的实现
    使用ReentrantLock探索过程,ReentrantLock锁的实现依赖AQS:使用一个整型volatile来维护同步状态,加锁时首先读取volatile变量state,解锁方法写state,使用cas方式设置state
    锁的执行字节码天机lock前缀:
    1)确保读改写操作的原子性,Intel使用缓存锁定来保证指令的原子性,大大降低执行开销
    2)禁止该指令,与之前好之后的读和写指令重排序
    3)把写缓冲区中的所有数据刷新到内存中
    锁释放和获取的内存语义实现方式:利用volatile变量的读写 利用cas操作带有的volatile读写的内存语义
  4. Concurrent包的实现
    CAS操作会使用处理器提供的高效机器级别的原子指令,在concurrent·包中,一个通用化的实现模式 声明共享变量volatile,然后使用CAS操作实现线程同步,同时配合读写带来的内存读写语义实现线程通信

3.6 final域的内存语义

  1. final域的重排序规则
    1)在构造函数内对一个final域的写入,域随后把这个被构造函数对象的引用赋值给一个引用变量,两个操作不能重排序
    2)初次读一个final域的对象的引用,与随后读取这个final域,这两个操作之间不能重排序

  2. JMM禁止把final域的写重排序到构造函数之外,编译器会在构造函数的return之前,插入一个StoreStore屏障

  3. 在一个线程中初次读取对象引用和初次读取这个对象包含的final时,JMM禁止处理器重排序这两个操作,会在读final域操作的前面加个LoadLoad屏障
  4. final域是引用类型是不能保证重排序

3.7 happens-before

JMM的核心概念,理解happens-before是理解JMM的关键
happens-before规则和as-if-serial规则语义相似,as-if-serial语义保证单线程程序的执行结果不被改变,happens-before保证正确同步的多线程程序的执行结果不被改变
JMM的设计:
程序员对内存模型的使用,易于理解易于编程,基于一个强内存模型编写代码;
编译器和处理器对内存模型的实现。编译器和处理器希望内存模型对它们的约束越来越少
重排序分为会改变结果的重排序和不会改变结果的重排序;对于会改变结果的要求禁止
happens-before规则:
happens-before规则

3.8 双重检查锁定与延迟初始化

3.9 内存模型综合描述

顺序一致性内存模型是理论参考模型,JMM和处理器内存模型在设计时会参考。
JMM的内存可见性保证:
1.单线程程序,不会出现内存可见性问题,编译器和处理器会共同保证单线程程序的执行结果
2.正确同步的多线程程序,将具有顺序一致性。这里是JMM关注的重点,JMM通过限制编译器和处理器的重排序为程序员提供保证内存可见性
3.未同步的多线程程序,JMM为它们提供最小的安全保障:线程在读取的值,要么是之前某个线程写入的值,要么是默认值在这里插入图片描述![
[1]: Java并发编程的艺术

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值