NOTICE:本文仅记录我对volatile关键字的一点理解,并没有详细记录每一点。如果有错误,可以指出一个对象的生成。一个javaClass对象的生成会经历以下几个阶段:类加载、验证、准备、分析、初始化类加载:通过类的全限定名获取类的二进制文件,转换成类中的Class对象JVM的方法区验证:验证Class对象的格式,包括文件格式验证、元数据验证、字节码验证、符号引用验证准备:为Class对象的静态变量分配内存并赋初始零value解析:将姜符号引用转换为直接引用初始化:如果运行时需要使用该Class对应的对象,则执行Class文件显式地为静态变量赋值当使用new关键字或newInstance方法时,JVM调用Class的meta信息,分出一块内存到堆中,放入运行时常量池中新建的对象。如果对象在虚拟机堆栈上,则它使用局部变量。该程序已执行,没有问题。但是如果你是在使用一个成员变量,并发修改它,想看它是否正确(可见性),那么其他的修改就需要修改并写回主存,并且最新的数据要拉回来的时候用过的。这就涉及到JAVA的内存模型和缓存一致性协议JAVA内存模型。JAVA内存模型主要分为两类:主内存和工作内存。它是主存的变量副本。这涉及主内存和工作内存的同步。它涉及到并发的三个特性和内存间交互操作的并发过程的三个特性。原子性。一个操作或多个操作要么执行成功,要么不执行类似于事务可见性,一个线程对一个变量进行操作,其他线程可以立即看到变化,解决了变化后线程间不一致的问题。Sequential程序执行顺序按照控制流顺序执行内存间交互操作lock[mainMemory]??标记一个变量为线程的独占状态memorytotheworkingmemoryload[workingmemory]??将读取过程中变量的值赋值给变量copyuse[workingmemory]??在代码中使用变量assign[workingmemory]将代码过程中改变的值赋值给theworkingmemoryvariablecopystore[workingmemory->mainmemory]??将workingmemory变量copy的值传回主存write[Mainmemory]??将返回值写回主存变量unlock并释放变量独占状态给定一个变量,它需要在主内存和工作内存之间进行复制。必须经过的步骤:read->load->use->assign->store->write如果想让一个线程独占这个变量,有两种方式:这个变量是局部变量,全局变量是用volatile修饰。缓存一致性协议MESIMESI是一个基于回写和缓存失效的协议状态机(CacheA/CacheB/Primarysave)状态改变前提动作Modify->Modify/localread/localwrite,状态不改变Modify->InvalidCacheA/B同时包含数据。缓存A已在前一个时间点更新。缓存B收到Invalid消息,缓存设置为InvalidModify->共享缓存A更新本地数据,缓存B没有数据缓存A写回主存,缓存B从主存中拉取最新数据缓存A数据从Modify->SharedstatepreconditionactionExclusive->Exclusive/CacheAlocalreadExclusive->ModifyCacheACacheExclusiveCacheAlocalwriteExclusive->SharedCacheACacheExclusiveCacheB读取主存数据,数据由Exclusive变为SharedExclusive->InvalidCacheACacheExclusiveCacheAlocalwrite,setthedataPrerequisiteactionforInvalidstatechangeShared->Shared/CacheAlocalread/CacheA/B同时读取相同的数据Shared->InvalidCacheA修改缓存CacheB接收到Invalid事件并将自己设置为InvalidShared->Modify/CacheA本地写入状态更改先决条件操作Invalid->InvalidcacheBcacheInvalidcacheAModifycache,cacheBcache从Invalid拉取最新数据InvalidInvalid->Shared/Exclusive/cacheB,如果cacheA有数据,则为Shared,否则ExclusiveInvalid->Modify/cacheA拉取最新数据,并本地写入,状态是JVM登陆的ModifyCacheConsistency--volatile关键字主要特点volatile修饰变量的修改对所有线程可见。通过在操作变量前后插入内存屏障,将易失性变量赋值并写回主内存。之后,通知其他线程该值已更改。详细步骤参考MESI协议的状态流程。Volatile禁止对机器指令重新排序。volatile不保证原子性。线程后续修改写回主存后,主存数据不一致。适用场景一次性重要事件,例如程序关闭和布尔变量赋值双重检查锁,防止指令重排序访问未初始化对象的底层实现volatile通过内存屏障实现可见性。在写操作之前插入StoreStorebarrier,保证在写操作之后插入StoreLoadbarrier,其他线程可见,保证其他线程在读取数据的时候,可以读取到最新的数据。在读操作之前,插入LoadLoad屏障,保证所有线程获取的数据是同一个读操作,插入LoadStore屏障,保证当前线程在其他线程修改之前获取到最新的值内存屏障barrier执行顺序解释LoadLoadLoad1->LoadLoad->Load2Load2读取数据之前,确保Load1读取数据并读取。StoreStoreStore1->StoreStore->Store2Store2写入并执行。确保Store1写入对其他处理器可见。在LoadStoreLoad1->LoadStore->Store2Store2写入和执行之前,确保Load1读取数据。在完成StoreLoadStore1->StoreLoad->Load2Load2之前,确保Store1写入对所有处理器可见让重新排序的CPU重新排序指令以提高运行效率,后面的代码可能会在前面的代码之前执行。重新排序还遵循似串行语义和先行原则。好像串行语义具有数据依赖性连续的操作不会被重新排序。happen-before原则首先发生。先发生的操作的影响可以通过后续的操作获得。分类表明程序顺序规则控制流程顺序。前面的代码必须在下面的代码之前执行。监听锁原理锁的加锁操作先于解锁操作执行。volatile变量原理。volatile变量的写操作在读操作之前执行。执行线程启动原理。线程的启动方法在任何线程操作之前执行。线程中断原则线程的中断方法调用先于任何检测到线程中断事件操作对象终结原则对象的初始化先于finalize方法调用完成传递性A->B,B->C,然后A->C
