• Java基础教程:多线程基础——内存模型


    Java基础教程:多线程基础——内存模型

    Java内存模型

      Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中提出变量这样的底层细节

    主内存与工作内存

      Java内存模型规定所有变量都存贮到主内存(如虚拟机物理内存中的一部分)中。每一个线程都有一个自己的工作内存(如cpu中的高速缓存)。线程中的工作内存保存了该线程使用到的变量的主内存的副本拷贝。线程对变量的所有操作(读取、赋值等)必须在该线程的工作内存中进行。不同线程之间无法直接访问对方工作内存中变量线程间变量的值传递均需要通过主内存来完成

      

     

    [!]此处的变量不同于Java编程中的变量,它包括了实例字段、静态字段和构成数组对象的元素,但是不包括局部变量和方法参数,因为后者是线程私有的,不会被共享,自然也不存在竞争问题。

    内存间的交互操作

      关于主内存与工作内存之间具体的交互协议,即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的实现细节,Java内存模型中定义了以下8种操作来完成,虚拟机实现时必须保证下面提及的每一种操作都是原子的、不可再分的:

    1. lock(锁定):作用于主内存中的变量,它把一个变量标识为一个线程独占的状态;
    2. unlock(解锁):作用于主内存中的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
    3. read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便后面的load动作使用;
    4. load(载入):作用于工作内存中的变量,它把read操作从主内存中得到的变量值放入工作内存中的变量副本
    5. use(使用):作用于工作内存中的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作;
    6. assign(赋值):作用于工作内存中的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作;
    7. store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送给主内存中以便随后的write操作使用;
    8. write(操作):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。

      把一个变量从主内存读取到工作内存,需要顺序执行read、load操作,把变量从工作内存同步到主内存,就要顺序执行store、write操作。但是上述操作可以是不连续的,即read a,read b,load a,load b,是可以接受的

      其他的一些限制还请查阅《深入理解Java虚拟机》。

    Volatile变量的特殊规则

      关键字volatile是Java虚拟机提供的最轻量级的同步机制,但是不容易被正确、完整的理解。

      当一个变量定义为volatile以后,就具有了两种特性:

    • 保证此变量对所有线程的可见性,即对volatile变量的写操作都是可以立刻反应到其他线程之中的
    • 禁止指令重排序

    对于Long、Double变量的特殊规则

      Java内存模型要求对lock、unlock、read、load、store、write、assign、use这8个操作都具有原子性,但是对于64位的数据类型(long/double),在模型种定义了一条相对宽松的规定:

      允许虚拟机将没有被volatile修饰的64位数据的读写操作划分为两次32位的操作来进行,即允许虚拟机实现选择可以不保证64为数据类型的load、store、read、write这4个操作的原子性。但目前各种平台的商用虚拟机几乎都已经把64位数据的读写操作作为原子操作来对待,所以我们编写代码时不需要将他们专门声明为volatile。

    原子性、可见性、有序性

    • 原子性:指一个操作的不可再分。8种原子操作及锁机制。
    • 可见性:指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。volatile关键字可以实现这一点。
    • 有序性:线程内表现为串行的语义、"指令重排序"现象和"工作内存与主内存同步延迟"现象。

    先行发生原则

      先行发生原则是判断数据是否存在竞争、线程是否安全的主要依据,定义了两项操作的偏序关系,如果说操作A先行发生于操作B,其实就是说发生操作B之前,操作A产生的影响能被操作B观察到,“影响”包括修改了内存种共享变量的值、发送了消息、调用了方法等

     

     

  • 相关阅读:
    C/C++中的堆、栈和队列
    网卡工作状态检测
    Delphi 2007 的midas程序注册问题
    使用SQL语句备份与恢复数据库
    C/C++中的堆、栈和队列
    Delphi 2007 的midas程序注册问题
    如何使用VirtualBox的共享文件夹(转)
    如何使用VirtualBox的共享文件夹(转)
    C语言struct的使用
    printf常用格式
  • 原文地址:https://www.cnblogs.com/MrSaver/p/8351032.html
Copyright © 2020-2023  润新知