Java内存模型与指令重排序

  1. java中的内存模型

    在这里插入图片描述

  2. java内存间的交互操作

    1. lock(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态
    2. unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的线程可以被别的线程锁定
    3. read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load操作使用
    4. load(载入):作用于工作内存的变量,把read操作从主内存中得到的值放入工作内存的副本中
    5. user(使用):作用于工作内存中的变量,把工作内存中的一个变量值传递给执行引擎
    6. assign(赋值):作用于工作内存中的变量,它把一个从执行引擎接收到的值赋给工作内存的变量
    7. store(存储):作用于工作内存的变量,把工作内存中一个变量的值传递到主内存中,一边随后的write操作
    8. write(写入):作用于主内存的变量,它把store操作从工作内存的一个变量的值传送到主内存的变量中
  3. 上面的8种操作必须满足一下规则

    1. 不允许read和load,store和write操作之一单独出现,即不允许一个变量从主内存读取了但工作内存不接受,或者从工作内存发起了会写但主内存不接受的情况出现
    2. 不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步会主内存
    3. 不孕与一个线程无原因的(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存
    4. 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量,换句话说,就是对一个变量实施user和store操作之前,必须先执行了assign和load操作。
    5. 同一个变量在同一时刻只允许一条线程对齐进行lock操作,但lock操作可以被一个线程重复执行多次,多次执行lock后只有执行相同次数的unlock操作,变量才会被解锁。
    6. 如果对一个变量执行lock操作,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load个assign操作初始化该变量的值。
    7. 如果一个变量事先没有被lock操作锁定,那就不允许对它执行unlock操作,也不允许unlock一个被其他线程锁定的变量
    8. 对一个变量执行unlock操作之前,必须先把此变量同步回主内存(执行store和write操作)。
  4. 先行发生原则happen-before(判断数据是否有竞争,线程是否安全的主要依据)

    1. 程序次序规则:同一个线程内,按照代码出现的顺序,前面的代码先行于后面的代码,准确的说就是控制流顺序,因为要考虑到分支和循环结构。
    2. 管程锁定规则:一个unlock操作先行发生于后面(时间上)对同一个锁的lock操作。
    3. volatile变量规则:对一个volatile变量的写操作先行发生于后面(时间上)对这个变量的读操作。
    4. 线程启动规则:Thread的start()方法先行发生于这个线程的每一个操作。
    5. 线程终止规则:线程的所有操作都先行发生于此线程的终止检测。可以通过Thread.join()方法结束,Thread.isAlive()的返回值等手段检测线程是否终止。
    6. 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断线程的发生,可以通过Thread.interrupt()方法检测线程是否中断。
    7. 对象终结原则:一个对象的初始化完成要先行发生于他的finalize()方法的开始。
    8. 传递性:如果操作A先行发生于操作B,操作B先行发生于操作C,那么操作A先行发生于操作C
  5. 无论jvm还是CPU,都希望程序运行的更快,如果两个操作不在上面罗列出来的规则里面, 那么就可以对它们进行任意的重排序(打乱它们的运行次序)。

  6. 时间先后顺序与现行发生的顺序之间基本没有关系。

  7. 指令重排序:编译器和处理器为了优化程序的性能而对指令序列进行重新排序的一种手段。

  8. 数据依赖性:编译器和处理器在冲排序时,会遵守数据依赖性,编译器和处理器不会改变存在依赖关系的两个操作的执行顺序(仅针对单个处理器中执行的指令和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑)。

  9. 两个操作访问同一个变量,并且这两个操作中至少有一个是写操作,此时就存在依赖性。

  10. as-if-serial原则:不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然可以!下面是一篇关于Java内存模型基础的博客,包含目录: ## 目录 1. 简介 2. Java内存模型概述 3. 主内存和工作内存 4. 内存交互操作 * 内存屏障 * volatile关键字 * synchronized关键字 5. 原子性、可见性和有序性 * 原子性 * 可见性 * 有序性 6. happens-before关系 7. synchronized关键字的使用 8. volatile关键字的使用 9. final关键字的使用 10. Java内存模型的实践 ## 1. 简介 Java内存模型Java虚拟机定义的一种抽象规范,用于描述多线程程序中,线程之如何通过内存进行通信,并保证线程之的可见性、有序性和原子性。 ## 2. Java内存模型概述 Java内存模型由主内存和工作内存组成。主内存是所有线程共享的内存区域,而每个线程都有自己的工作内存,用于存储主内存中的变量副本。 ## 3. 主内存和工作内存内存是所有线程共享的内存区域,用于存储对象实例、静态变量和类信息等。而每个线程都有自己的工作内存,用于存储主内存中的变量副本。 ## 4. 内存交互操作 为了保证线程之的通信和数据一致性,Java提供了多种内存交互操作,包括内存屏障、volatile关键字和synchronized关键字。 ### 4.1 内存屏障 内存屏障是一种同步机制,用于确保某些操作的执行顺序。它可以防止指令排序内存访问排序,保证线程之的有序性。 ### 4.2 volatile关键字 volatile关键字用于修饰变量,保证线程之对该变量的可见性和禁止指令排序。当一个线程修改了volatile变量的值,其他线程能够立即看到最新的值。 ### 4.3 synchronized关键字 synchronized关键字用于修饰方法或代码块,实现线程之的互斥访问和对共享数据的同步操作。它可以保证多个线程对同一个对象的同步访问。 ## 5. 原子性、可见性和有序性 Java内存模型中的三个要概念是原子性、可见性和有序性。 ### 5.1 原子性 原子性是指一个操作是不可中断的,要么全部执行成功,要么全部不执行。Java中的原子操作包括基本数据类型的赋值和读取,以及引用类型的赋值和读取。 ### 5.2 可见性 可见性是指当一个线程修改了共享变量的值时,其他线程能够立即看到最新的值。volatile关键字和synchronized关键字都能保证可见性。 ### 5.3 有序性 有序性是指程序执行的结果按照一定的顺序展现给外部观察者。Java内存模型通过happens-before关系来保证有序性。 ## 6. happens-before关系 happens-before关系是Java内存模型中定义的一种偏序关系,用于判断两个操作是否具有happens-before关系。它可以保证多线程程序的正确性。 ## 7. synchronized关键字的使用 synchronized关键字用于修饰方法或代码块,实现线程之的互斥访问和对共享数据的同步操作。它可以保证多个线程对同一个对象的同步访问。 ## 8. volatile关键字的使用 volatile关键字用于修饰变量,保证线程之对该变量的可见性和禁止指令排序。当一个线程修改了volatile变量的值,其他线程能够立即看到最新的值。 ## 9. final关键字的使用 final关键字用于修饰类、方法和变量,具有不可变性和安全性的特性。它可以保证被final修饰的变量在多线程环境下的安全访问。 ## 10. Java内存模型的实践 在实际开发中,合理地使用Java内存模型的各种特性和机制,可以提高多线程程序的性能和可靠性。本章将介绍一些常见的实践方法和技巧。 以上是关于Java内存模型基础的博客的目录,希望对你有所帮助!如有任何问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值