月眸


java并发与高并发学习系列1:java内存模型

毛毛小妖 2019-03-06 275浏览 0条评论
首页/ 正文
分享到: / / / /

一、定义

      Java内存模型规定了一个线程如何和何时可以看到由其他线程修改过后的共享变量的值,以及在必须时如何同步的访问共享变量。

二、java内存分配 

      堆和栈,参考java种堆和栈的区别

三、计算机硬件架构

       一个现代计算机通常由两个或者多个CPU。其中一些CPU还有多核。从这一点可以看出,在一个有两个或者多个CPU的现代计算机上同时运行多个线程是可能的。每个CPU在某一时刻运行一个线程是没有问题的。这意味着,如果你的Java程序是多线程的,在你的Java程序中每个CPU上一个线程可能同时(并发)执行。

1>寄存器

      每个CPU都包含一系列的寄存器,它们是CPU内内存的基础。CPU在寄存器上执行操作的速度远大于在主存上执行的速度。这是因为CPU访问寄存器的速度远大于主存。

2>缓存层

      每个CPU可能还有一个CPU缓存层。实际上,绝大多数的现代CPU都有一定大小的缓存层。CPU访问缓存层的速度快于访问主存的速度,但通常比访问内部寄存器的速度还要慢一点。一些CPU还有多层缓存,但这些对理解Java内存模型如何和内存交互不是那么重要。只要知道CPU中可以有一个缓存层就可以了。

3>主存

      一个计算机还包含一个主存。所有的CPU都可以访问主存。主存通常比CPU中的缓存大得多。

      通常情况下,当一个CPU需要读取主存时,它会将主存的部分读到CPU缓存中。它甚至可能将缓存中的部分内容读到它的内部寄存器中,然后在寄存器中执行操作。当CPU需要将结果写回到主存中去时,它会将内部寄存器的值刷新到缓存中,然后在某个时间点将值刷新回主存。

      当CPU需要在缓存层存放一些东西的时候,存放在缓存中的内容通常会被刷新回主存。CPU缓存可以在某一时刻将数据局部写到它的内存中,和在某一时刻局部刷新它的内存。它不会再某一时刻读/写整个缓存。通常,在一个被称作“cache lines”的更小的内存块中缓存被更新。一个或者多个缓存行可能被读到缓存,一个或者多个缓存行可能再被刷新回主存。

四、Java内存模型和硬件内存架构之间的桥接

      上面已经提到,Java内存模型与硬件内存架构之间存在差异。硬件内存架构没有区分线程栈和堆。对于硬件,所有的线程栈和堆都分布在主内中。部分线程栈和堆可能有时候会出现在CPU缓存中和CPU内部的寄存器中。如下图所示:

五、java内存模型抽象结构图

      线程之间共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存是java内存模型一个抽象的概念,并不是真实存在的,它涵盖了缓存,写缓存区,寄存器以及其他硬件和编译器的优化。本地内存存储了该线程以读或共享变量的拷贝副本,如果该线程要使用主内存的一个变量,就会先把主内存的变量拷贝出来放到自己的本地内存中。从更低的层次来说,主内存就是硬件的内存,是为了获取更好的运行速度,虚拟机和硬件系统可能会让工作内存优先存储于寄存器或高速缓存中。java内存模型中的线程工作内存其实就是高速缓存和寄存器的一个抽象的描述。

六、线程通信

      线程A从主内存中拿到变量a存储到自己的本地内存中,执行操作完再写入到主内存,同时线程B也从主内存中拿到变量a存储到自己的主内存中,执行操作后再写入到主内存中,这个过程中很可能发生错误。

七、Java内存同步的8种操作及规则

1>八种操作

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

    如果要把一个变量从主内存中复制到工作内存,就需要按顺寻地执行read和load操作,如果把变量从工作内存中同步回主内存中,就要按顺序地执行store和write操作。Java内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行。也就是read和load之间,store和write之间是可以插入其他指令的,如对主内存中的变量a、b进行访问时,可能的顺序是read a,read b,load b, load a。

2>八种规则

1、不允许read和load、store和write操作之一单独出现
2、不允许一个线程丢弃它的最近assign的操作,即变量在工作内存中改变了之后必须同步到主内存中。
3、不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中。
4、一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量。即就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。
5、一个变量在同一时刻只允许一条线程对其进行lock操作,lock和unlock必须成对出现
6、如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行load或assign操作初始化变量的值
7、如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。
8、对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)。

最后修改:2019-03-06 09:23:53 © 著作权归作者所有
如果觉得我的文章对你有用,请随意赞赏
扫一扫支付

上一篇

发表评论

说点什么吧~

评论列表

还没有人评论哦~赶快抢占沙发吧~