说到并发编程,就不得不提到并发的三要素:原子性、可见性和有序性,而Volatile会涉及到可见性和有序性,它可以是可见,Volatile在并发编程中起着重要作用。因此,有必要重点掌握Volatile。为了帮助大家掌握Volatile,我将重点介绍以下5点:1.Volatile关键字2.Java内存模型3.Volatile内存模型可见性4.Volatile工作原理5.Volatile案例源码在说Volatile之前,下面我们来回顾一下Java内存模型的三要素:原子性、可见性、顺序,这是经常被提及的并发编程的三要素。并发编程的三要素1、原子性与数据库事务中的原子性是一样的。满足原子性特性的操作是不可中断的。要么所有执行成功,要么所有执行失败。只有简单的读取和赋值(而且必须是数字赋值给一个变量,变量之间的相互赋值不是原子操作)才是原子操作。例如:i=2;j=我;我++;我=我+1;上面4个操作中,i=2是读操作,肯定是原子操作,j=i你以为是原子操作,其实分两步,一个是读i的值,然后赋值给j,这是2步操作,不是原子操作,i++和i=i+1其实是等价的,读取i值,加1,然后写回主存,也就是一个3-步骤操作。因此,在上面的例子中,最终值可能会出现在各种情况下,因为无法满足原子性。非原子操作会存在线程安全问题,我们需要使用同步技术(sychronized)使其成为原子操作。java的并发包提供了一些原子类:例如:AtomicInteger、AtomicLong等。2.可见性当多个线程访问同一个共享变量时,如果其中一个线程修改了共享变量的值,其他线程可以立即获取到修改值3.有序的编译器和处理器优化程序性能指令序列是重新排序的,也就是你写的代码的顺序和最终执行的指令的顺序不一致。但是重排序过程不会影响单线程程序的执行,但是会影响多线程并发执行的正确性。VolatileVolatile是Java语言的一种类型修饰符。一个共享变量(类成员变量,类静态成员变量)一旦被Volatile修饰,它有两层语义:1.多线程下保证可见性2.禁止指令重新排序(即保证顺序).这里有一个需要注意的问题。volatile只能让他修改的内容可见,有序。volatile只能保证单次读写的原子性,i++操作不能保证原子性。易失性内存模型Java内存模型(JMM)是一个并不真正存在的抽象概念。它描述了一组规则或规范,通过这些规则或规范定义了程序中的每个变量(包括实例字段、静态字段和组件)。数组对象的元素)。它试图屏蔽各种硬件和操作系统的内存访问差异,使Java程序在各种平台上都能达到一致的内存访问效果。Java内存模型规定所有的变量都存放在主存中,每个线程都有自己的工作内存。线程的工作内存存储线程中使用的变量的主内存副本的副本。所有操作都必须在工作内存中进行,不能直接读写主内存。不同的线程不能直接访问对方工作内存中的变量,线程间变量的传递需要自己的工作内存和主存之间进行数据同步。主存主要存放Java实例对象,线程创建的所有实例对象都存放在主存中,当然不管实例对象是成员变量还是方法中的局部变量(也叫局部变量),它还包括共享类。信息、常量、静态变量。由于是共享数据区,多个线程在访问同一个变量时可能会发现线程安全问题。工作内存每个线程都有自己的工作内存(WorkingMemory,也称为本地内存,可以类比前面介绍的处理器缓存),线程的工作内存保存了线程使用的主内存中的变量。共享变量的副本。工作记忆是JMM的抽象,并不真实存在。它涵盖了高速缓存、写入缓冲区、寄存器以及其他硬件和编译器优化。主要存放当前方法的所有局部变量信息(变量在主存中的副本存放在工作内存中),每个线程只能访问自己的工作内存,即线程中的局部变量是对其他线程不可见,即使是两个线程执行一段代码,它们也会各自在自己的工作内存中创建属于当前线程的局部变量,当然包括字节码行号指示符和Native的相关信息方法。Volatile实现原理Volatile保证内存可见性主存和工作内存的交互有特定的交互协议。JMM定义了八个操作来完成。这八个操作是原子的,不可分割的。它们是:lock、unlock、read、load、use、assign、store、write,其中lock、unlock、read、write作用于主存;加载、使用、分配、存储作用于工作记忆。(1)lock:锁住主存中的变量,一个线程独享(2)unclock:解锁lock加的锁,此时其他线程才有机会访问这个变量(3)read:在主内存中设置变量将变量的变量值读入工作内存中(4)加载:将read读取的值保存到工作内存中的变量copy中。(5)use:将值传递给线程的代码执行引擎(6)assign:将执行引擎处理返回的值重新赋值给变量copy(7)store:将变量copy的值存入主存.(8)write:将store存储的值写入主存的共享变量。将变量从主存复制到当前工作内存(读取和加载)执行代码,改变共享变量的值(使用和赋值)用工作内存数据(存储和写入)指令刷新主存相关内容规则read和load、store和write必须assign操作成对出现。工作内存变量改变后,必须刷新回主内存。同一时间只能运行一个线程来锁定变量。当前线程锁是可重入的,解锁次数必须等于锁的次数才能解锁变量。变量上锁后,线程工作内存中的变量值会被清空,再次执行load或assign操作,初始化工作内存中的变量值。解锁前必须将变量同步到主存(存储/写入操作)Volatile源码案例以上就是Java并发编程中Volatile实现原理的介绍。希望你能有所收获!-END-作者简介:mikechen,十余年BAT架构经验,资深技术专家,曾就职于阿里、淘宝、百度。关注个人公众号:Mikechen的互联网架构,十余年BAT架构经验!在公众号菜单栏对话框中回复【架构】关键字,即可查看我原创的300+BAT架构技术系列文章和1000+大厂面试问答合集。
