您好、欢迎来到现金彩票网!
当前位置:2019跑狗图高清彩图 > 先行指令站 >

Java并发编程--volatile关键字

发布时间:2019-07-31 10:17 来源:未知 编辑:admin

  很久之前就想写volatile关键字,但是迟迟没有动笔,主要是volatile涉及到的东西有点多,讲不清楚倒还好,就怕反而把读者绕晕了,哈哈。

  volatile关键字是为了保证内存可见性及有序性的,首先介绍并发编程中涉及到的3个问题:

  原子具有不可分割性,所谓原子性,指的是一个或多个操作,要么全部执行且执行过程不会被任何因素打断,要么就全部执行,其与事务的语义是一致的。

  如果上述操作是非原子的,假如步骤1执行成功,而步骤2则异常中断,此时就会造成小明平白无故丢失了1000元。

  在Java中,主要通过synchronized关键字、Lock接口来实现多个操作的原子性。

  所谓可见性,指的线程之间的可见性,一个线程修改的状态对另外的线程是可见的。

  程序本来就是按照代码顺序来执行的呀,为啥还要保证?一切因为**指令重排序(Instruction Reorder)**的存在。

  处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。

  答案是不可能,因为指令重排序会分析语句间的数据依赖性,假设语句B依赖于语句A,即语句B需要使用语句A的结果,则不会发生指令重排序。

  所以,单线程环境下,指令重排序只是为了提高运行速度,并不会影响运算结果,但多线程环境下呢,看以下语句:

  上面代码中,由于语句1和语句2没有数据依赖性,因此可能会被重排序。假如发生了重排序,在线,而此是线会以为初始化工作已经完成,那么就会跳出while循环,去执行doSomethingwithconfig(context)方法,而此时context并没有被初始化,就会导致程序出错。

  volatile关键字是与Java内存模型紧密相关的,所以我们先简单讲解一下Java的内存模型。

  众所周知,CPU在执行程序指令的过程中,势必涉及到数据的读取和存入,运行过程中的中间数据存储在物理内存中。

  物理内存的数据存取速度和CPU的运行速度相比,基本等同于蜗牛和波音747,所以高速缓存出现了。

  高速缓存的速度虽然还是比不上CPU,但是比物理内存(主内存)还是要快多了。

  所以程序进行计算时,会将需要用到的数据先从主内存取到高速缓存中,然后CPU从高速缓存中取数据进行计算,计算的中间结果存入高速缓存,计算结束后将结果由高速缓存刷新到主内存。

  上述模式在单线程环境下没有问题,但是多线程下可能就会出问题,比如简单的i++操作:

  假设线程A和线程B分别执行了i++操作,理论上最终结果应该为2,但实际上也可能为1。

  如果线程A和B同时执行了步骤1,此时线程A和B的高速缓存中的值均为0,完成+1操作后分别刷新到主内存中,最终结果为1,即出现了缓存一致性问题。

  在早期的CPU当中,是通过在总线上加LOCK#锁的形式来解决缓存不一致的问题。因为CPU和其他部件进行通信都是通过总线来进行的,如果对总线加LOCK#锁的话,也就是说阻塞了其他CPU对其他部件访问(如内存),从而使得只能有一个CPU能使用这个变量的内存。比如上面例子中 如果一个线程在执行 i = i +1,如果在执行这段代码的过程中,在总线上发出了LCOK#锁的信号,那么只有等待这段代码完全执行完毕之后,其他CPU才能从变量i所在的内存读取变量,然后进行相应的操作。这样就解决了缓存不一致的问题。

  但是上面的方式会有一个问题,由于在锁住总线期间,其他CPU无法访问内存,导致效率低下。

  所以就出现了缓存一致性协议。最出名的就是Intel 的MESI协议,MESI协议保证了每个缓存中使用的共享变量的副本是一致的。它核心的思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。

  Java内存模型具备一些先天的有序性,即不需要通过任何手段就能够得到保证的有序性,这个通常也称为happens-before原则。如果两个操作的执行次序无法从happens-before原则推导出来,那么它们就不能保证它们的有序性,虚拟机可以随意地对它们进行重排序。

  程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作。

  volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作。

  传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C。

  线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作。

  线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生。

  线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行。

  对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始。

  volatile变量规则指的是如果一个线程先去写一个变量,然后一个线程去进行读取,那么写入操作肯定会先行发生于读操作。

  介绍了并发编程规则及Java的内存模型,下面我们深入分析一下volatile关键字:

  inited由volatile修饰后,则语句1和语句2不会发生重排序,保证inited = true时,运行上下文context必定加载完毕,从而避免了上述多线程下的运行异常。

  观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令。

  lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:

  它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;

  之所以instance需要使用volatile修饰,是因为下述语句可能会发生指令重排序:

  假设步骤1、2发生了重排序,即步骤2在步骤1之前执行,当其他读取线程进行单例读取时,此时步骤2已执行完成,读取线程判断instance非null,故进行读取,但此时步骤1可能还未完成,即对象还未初始化完成,从而导致读取线程发生异常。

  instance添加volatile关键字后,步骤1和2禁止指令重排序,从而避免了上述问题。

  相信很多人对于volatile关键字既熟悉又陌生,熟悉是对这个名字很熟悉,陌生是对他的原理和用法很陌生,最近几天通过查阅大量资料和书,终于对volatile有了一定的理解,写此博客一来做了记录,二来使...博文来自:阿拉灯神灯的专栏

  在接触并发编程之前我对volatile关键字是没有什么映像的,这个关键字解决了什么问题呢?让我们先来看一个示例:publicclassUseVolatitleextendsThread{private...博文来自:张翠山的博客

  首先了解一下并发编程的一些内容:介绍线程之间读取数据的流程 原子性 可见性: 有序性:  开始介绍volatile关键字的作用:但...博文来自:emmmsuperdan的博客

  前言对于ThreadLocal、Volatile、synchronized、Atomic这四个关键字,我想一提及到大家肯定都想到的是解决在多线程并发环境下资源的共享问题,但是要细说每一个的特点、区别、...博文来自:【博客地址迁移到】:

  1.保持可见性2.禁止进行指令的重排序(volatile关键字能确保变量在线程中的操作不会被重排序而是按照代码中规定的顺序进行访问)...博文来自:一直在路上

  文章目录1.JMM解决原子性、可见性、有序性的问题1.1原子性保障1.2可见性1.3有序性2.volatile如何保证可见性3.volatile防止指令重排序3.1内存屏障4.Volatile原子性问...博文来自:Visonws的博客

  介绍Volatile之前,先要引入多线程的三个特性多线程三大特性多线程有三大特性,原子性、可见性、有序性1.原子性:一个操作或者多个操作要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行例如...博文来自:y_mk的博客

  作用保证不同线程对volatile修饰的变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。禁止进行指令重排序。volatile的可见性publicclassTes...博文来自:a1102325298的博客

  1.volatile的定义与实现原理:java语言允许访问共享变量,为了能够确保共享变量能被准确和一致性更新,线程应该通过排它锁单独获得这个共享变量。java提供volatile关键字,确保所有线程看...博文

  volatile关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见。相较于synchronized是一种较为轻量级的同步策略。缺点:1.volatile不具备“互斥性”2.volatile...博文来自:BushRo

  1.并发编程的两个关键问题并发是让多个线程同时执行,若线程之间是独立的,那并发实现起来很简单,各自执行各自的就行;但往往多条线程之间需要共享数据,此时在并发编程过程中就不可避免要考虑两个问题:通信与同...博文来自:大闲人柴毛毛

  volatile关键字在c、java中都有,用于修饰变量,例如privatevolatileinti;它在多处理器开发环境中保证了共享变量的“可见性”,即当一个线程修改一个共享变量时,另外一个变量能读...博文来自:l577217的博客

  根据《java多线程编程核心技术》整理总结关键字volatile的主要作用是使变量在多个线.volatile关键字简介下面我们通过代码示例来理解volatile关键字的作用publiccl...博文来自:睁眼看世界

  一.volatile关键字是什么?当一个变量定义为volatile之后,它将具备两种特性:  ①保证此变量对所有线程的可见性    当一条线程修改了这个变量的值,新值对于其他线程可以说是可以立即得知的...博文来自:李子的博客

  volatile关键字能保证可见性和有序性,但是不保证原子性。因此并不能保证线程安全。看一个相关的例子:双重校验锁实现的单例模式:publicclassDoubleCheckSymbol{privat...博文来自:风行天下

  前言在Java中,Java中volatile关键字十分重要本文全面amp;详细解析volatile关键字,希望你们会喜欢目录1.定义Java中的1个关键字/修饰符2.作用保证被volatil...博文来自:专注分享 Android开发 干货

  -Transient关键字Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个...博文来自:龙吟的专栏

  内存模型与CPU缓存本来CPU计算的数字都是从主从mainmemory中读取的,但是CPU运行的速度比计算机读取内存的速度快,为了补齐这个短板,所以出现了CPU缓从这种东西。在多CPU系统(或多核处理...博文来自:Matthewhou的专栏

  1.synchronized关键字目的:synchronized关键字是java提供的锁机制,主要解决线程的同步问题,那么它可以修饰方法和同步代码块,那么问题来了,我们什么时候用同步代码块和方法呢,我...博文来自:HashMap原理认识

  前言在理解volatile前,先理解原子性、可见性、有序性原子性:操作的不可分割性。如++count实际上是可以分割的三个独立操作,读取-gt;修改-gt;写入,其结果依赖之前的状...博文来自:zl_momomo的博客

  Java的volatile关键字在JDK源码中经常出现,但是对它的认识只是停留在共享变量上,今天来谈谈volatile关键字。volatile,从字面上说是易变的、不稳定的,事实上,也确实如此,这个关...博文来自:x

  前一篇文章中提到原子操作,也许大家和我一样很好奇为什么rement方法能保证原子性,而简单的++运算却不能保证原子性。这篇文章我们就从AtomicInteger类下手...博文来自:胡飞飞的学习笔记

  三、Volatile关键字   关键字volatile的主要作用是使变量在多个线关键字volatile与死循环测试案例:我想通过改变flag的值,从而停止对service的test()...博文来自:绝版灬小伙的博客

  PS:本文主要为梳理自己基于收集的资料从而对volatile关键字的一些理解做整理,初次收集、梳理肯定有所不足,后续会基于自己了解的深入而修整,如果你不幸看到该篇内容请仅做初步参考,切勿掉坑。参考文章...博文来自:dengdai123654的博客

  这篇文章将并发编程的概念讲得很清楚:点击打开链接Java并发编程:volatile关键字解析从并发编程的三个概念讲起:原子性、可见性、有序性。原子性(整体,要么执行、要么不执行)可见性(当前的修改使后...博文来自:独钓寒江雪

  今天来分析一下volatile在并发编程里的作用。一、java内存模型的相关概念1、线程之间的通信机制:共享内存和消息传递。2、java内存模型的抽象结构:线程之间共享的变量存储在主内存中,而每个线程...博文来自:peerless_fu的博客

  1.为什么需要volatile关键字1.1所谓多线程变量“不可见”问题volatile关键字修饰的变量可以在多个线程之间保持“可见性”。这样的解释有些抽象,我们来看一个例子。假设下面这种场景:我们来模...博文来自:weixin_34402408的博客

  对Java现有二十三种设计模式之一的单例模式的一种实现思路私有的构造方法私有的单实例对象引用公有的供外部访问单实例的方法使用双重锁检查机制,提高安全性,且降低了锁力度不太耗费性能,只在初次创建对象时加...博文来自:如果能思维清晰,从上往下,不断深入,就好了~~~

  volatile关键字的作用是告诉编译器,凡是被该关键字申明的变量都是易变的、不稳定的,所以不要试图对该变量使用缓存等优化机制,而应当每次都从他的内存地址中去读取值,但volatile并不是每次更改完...博文来自:YEN_CSDN的博客

  synchronized关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized,但是要注意volatile关键字是无法...博文来自:maoxian007的专栏

  在网络上找了好多关于volatile的文章,一直没有找到体现volatile作用的代码示例,本文通过代码给大家介绍一下volatile的作用。如有不正之处,欢迎批评指正。示例一:publicclass...博文来自:天将降大任于是人

  Java并发编程之volatile关键字的理解     Java中每个线程都有自己的工作内存,类比于处理器的缓存,线程的工作内存中保存了被该线程使用到的变量的主内存的拷贝。线程读写变量都是直接在自己的...博文来自:莫名的拉风的博客

  本文主要介绍了volatile关键字的特性和用法博文来自:HappyFeet的博客

  在日常写java代码的环境下(不是研究计算机理论的情况)是会观测到内存可见性所带来的一些问题,比如下面这段代码:publicclassReorderingDemo{staticbooleanflag=...博文来自:WK_SDU的博客

  转载请备注地址:系列文章传送门:Java多线程学习(一)Java多线程入门Java多...博文来自:不忘初心

  Java代码在编译后会变成Java字节码,字节码被ClassLoader加载到JVM中,JVM执行字节码,最终要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和CPU的指令...博文来自:congyh的专栏

  在多线程中,volatile关键字是很重要的一个知识点,在多线程共享资源的时候,每个线程数据对外都是不可见的,这就容易出现”脏读”现象,其实就是线程私有堆栈中的数据和公共堆栈中的数据不同步造成的.解决...博文来自:charles_lun专栏

  内存可见性volatile是Java提供的一种轻量级的同步机制,在并发编程中,它也扮演着比较重要的角色。同synchronized相比(synchronized通常称为重量级锁),volatile更轻...博文来自:Yourbatman的博客

  使用volatile关键字修饰共享变量可以禁止重排序。若用volatile修饰共享变量,在编译时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序volatile禁止指令重排序的一些规则:...博文来自:ustcyy91的博客

  作为一个菜鸟,我学习volatile都只能了解个大概,都是给我一堆花里胡哨的废话,举例没一个是有用的,因此我总觉得volatile关键件没啥卵用,为啥,看看别人给的例子这里有volatile和没vol...博文来自:u013317158的博客

  概述:本文主要介绍Java语言中的volatile关键字,内容涵盖volatile的保证内存可见性、禁止指令重排等。...博文来自:代码改变世界

  Volatile关键字的粗浅理解在学习并发编程的时候了解到,volatile关键字有两个作用:1.并发环境可见性:volatile修饰后的变量能够保证该变量在线程间的可见性,线程进行数据的读写操作时将...博文来自:的博客

http://deafbook.net/xianxingzhilingzhan/379.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有