还是那句话,无论语言再怎么牛,其都是对底层计算机指令的封装。 计算机CPU执行指令的时候是非常快的,如果每执行一个指令都从内存中取数据的话,那会非常慢,严重影响CPU的执行速度,所以每个CPU都有自身对应的高速缓冲区(多级寄存器),每个线程被执行的时候,会先把运行时需要的数据复制到告诉缓冲区一份,此高速缓存区只与在该CPU运行的线程有关,然后在当前线程需要CPU执行N多指令的时候,就不用再去内存中拿数据,直接从本地的缓冲区,进而提高CPU的执行任务速度,等待执行完毕后再把结果写入到主内存中,但是什么时候执行结果会被刷新至主内存中是不太确定的(但是肯定在执行下一指令之前,哈哈);在遇到线程放弃执行权限或者sleep一段时间后等再次被处理器运行的时候,会重新把需要的数据载入高速缓冲区中。 上面这个结构,对于单CPU来说没有任何问题,但是近代计算机一般都是多个CPU,这样一来,每个CPU的高速缓冲区如果同时缓存了共享变量的话,那么就有可能出现数据状态不一致的情况,那么这个情况怎么解决呢?两个解决方案: 缓存一致性协议也称MESI协议: 它们之间的关系如下: JVM的内存屏障其实也是对计算机内存屏障的封装,其兼容了不容平台的差异,通过调用硬件的内存屏障指令来实现禁止指令重排。 执行上面这段程序,你会发现程序会一直运行,但是将exit变量声明为volatile的时候,2s就停止了。 有不对的地方,欢迎大家指正!
基础知识回顾
术语
释义
共享变量
可以被多个线程同时访问的变量
内存屏障
一组处理器指令,用于对内存操作的(指令)顺序限制
缓冲行
缓存中可以分配的最小存储单位
Volatile的实现原理
处理器的内存屏障分为两种:Load Barrier 和 Store Barrier即读屏障和写屏障。
分类
说明
StoreStore
禁止上面的普通写和下面的volatile写重排序
StoreLoad
防止上面的volatile写与下面可能有的volatile读/写重排序
LoadLoad
禁止下面所有的普通读操作和上面的volatile读重排序
LoadStore
禁止下面所有的普通写操作和上面的volatile读重排序
JMM内存模型与上面说的类似,对于共享变量每个线程都会对其生成变量副本,在后续的读写操作中都是操作其副本,等待对变量操作完毕后,再把变量副本写入到主内存中(不是实时写入主内存),如果遇到多个线程同时读写共享变量的时候,由于他们都是操作的副本,所以各个线程之间是互不知晓的,那么怎么让其中一个线程修改变量的时候,另外一个线程立马就知道呢?通过对volatile修饰的共享变量相关代码进行编译生成的汇编指令发现,volatile写操作对应的指令是一个lock前缀指令,而lock前缀指令会在多核CPU同时运行的情况下引发两件事:
JMM内存模型验证
private static boolean exit = false; public static void main(String[] args) throws InterruptedException { new Thread(()->{ while(!exit) { // try { // System.out.println("continue..."); // Thread.currentThread().sleep(1000); // } catch (InterruptedException e) {} } System.out.println("over..."); }).start(); Thread.currentThread().sleep(2000); exit = true; }
但是你把try代码块注释打开的话,那么你会发现虽然exit变量不是volatile的,但是程序也会在2停止,为什么呢?猜测原因有二:
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算