Java内存模型和volatile关键字怎么掌握

61次阅读
没有评论

共计 2210 个字符,预计需要花费 6 分钟才能阅读完成。

这篇文章主要讲解了“Java 内存模型和 volatile 关键字怎么掌握”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着丸趣 TV 小编的思路慢慢深入,一起来研究和学习“Java 内存模型和 volatile 关键字怎么掌握”吧!

java 内存模型(JMM):

相关概念:1)在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递。2)java 的并发采用的是共享内存模型:通过读 / 写内存中的公共状态进行隐式通信。概念:java 线程之间的通信是由 java 内存模型控制的,JMM 决定一个线程对共享变量的写入何时对另一个线程可见。1 线程之间的共享变量存储在主内存中,每个线程都有一个私有的工作内存,工作内存中存储了该线程读 / 写共享变量的副本。2 工作内存是 JMM 的一个抽象概念,并不真实存在。它涵盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优化。3 线程对变量的所有操作 (读取、赋值等) 都必须在工作内存中进行,而不能直接读写主内存中的变量。4 不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。

volatile 关键字:

相关概念:
 缓存行:缓存器中可以分配的最小存储单位。L1 缓存:内部缓存。L2 缓存:外部缓存。1)为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存中的数据读到缓存 (L1、L2) 后再进行操作,但操作完成后,处理器是不知道何时要把操作后的数据写回到内存中。2)对 volatile 修饰的变量进行写操作时,JVM 会向处理器发送一条 Lock 前缀的指令,将这个变量所在缓存行 (即 JMM 中的工作内存) 的数据写回到系统内存中,并且将其它 CPU 里缓存了该内存地址的数据无效。1 对 volatile 修饰的变量进行写操作 (赋值) 时,在 JIT 编译器生成的汇编指令中,我们会发现有一个以 Lock 为前缀的指令。2 以 Lock 为前缀的指令在多核处理器下会引发了两件事情:①将当前处理器缓存行的数据写回到系统内存中  ②这个写回内存的操作会导致其它 CPU 里缓存了该内存地址的数据无效。volatile 的内存原语:当读一个 volatile 变量时,JMM 会把该线程对应的工作内存置为无效,线程接下来将从主内存中读取共享变量。当写一个 volatile 变量时,JMM 会把该线程对应的工作内存中的共享变量值刷新到主内存。1 将本地内存中的数据设置为无效, 
 2 从主内存中将数据复制到本地内存中, 
 3 在本地内存中进行操作, 
 4 操作完成后将本地内存中的数据刷新到主内存中。整体看起来就像是直接在主内存中操作一样。 

用 volatile 修饰的变量如果被一个线程更改了,那么其它的线程都会立即感知,并且每个线程获取该变量的值都是最新的值,访问 volatile 修饰的变量看起来就像是直接在内存中读写一样。可见性:对一个 volatile 变量的读,(任意线程)总是能看到对这个 volatile 变量最后的写入。原子性:对一个 volatile 变量的读 / 写具有原子性,但类似于 volatile++ 这种复合操作不具有原子性。不会引起线程上下文的切换
volatile 与 synchronized 的比较:1)关键字 volatile 只能修饰变量,synchronized 可以修饰代码块、方法 2)volatile 不能保证原子性,synchronized 保证原子性:volatile 可以保证数据的可见性,但是不能保证原子性,所以 volatile 解决的是变量在多线程之间的可见性;synchronized 可以保证原子性,也保证了可见性(synchronized 会将私有内存和公共内存中的数据做同步),所以 synchronized 解决的是多线程之间访问资源的同步性。

重排序:

说明:在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序。重排序分 2 种类型:1)编译器重排序:编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。2)处理器重排序:1 指令级并行的重排序:现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。2 内存系统的重排序:  由于处理器使用缓存和读 / 写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
两个操作间重排序的条件:1 当第一个操作是 volatile 读,不管第二个操作是什么,都不能重排序。这个规则确保 volatile 读之后的操作不会被编译器重排序到 volatile 读之前。2 当第二个操作是 volatile 写,不管第一个操作是什么,都不能重排序。这个规则确保 volatile 写之前的操作不会被编译器重排序到 volatile 写之后。3 当第一个操作是 volatile 写,第二个操作是 volatile 读时,不能重排序。由以上 3 点可以得出结论:两个 volatile 变量操作不能够进行重排序。2)为了实现 volatile 的内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。(内存屏障:将前面操作的共享变量值刷新到主内存中。)

感谢各位的阅读,以上就是“Java 内存模型和 volatile 关键字怎么掌握”的内容了,经过本文的学习后,相信大家对 Java 内存模型和 volatile 关键字怎么掌握这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是丸趣 TV,丸趣 TV 小编将为大家推送更多相关知识点的文章,欢迎关注!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-16发表,共计2210字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)