volatile

首先了解下Java 内存模型中的可见性、原子性和有序性。

可见性:

  可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉。通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。

  可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果。另一个线程马上就能看到。比如:用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。但是这里需要注意一个问题,volatile只能让被他修饰内容具有可见性,但不能保证它具有原子性。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,也就是这个操作同样存在线程安全问题。

  在 Java 中 volatile、synchronized 和 final 实现可见性。

原子性:

  原子是世界上的最小单位,具有不可分割性。比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。一个操作是原子操作,那么我们称它具有原子性。java的concurrent包下提供了一些原子类,我们可以通过阅读API来了解这些原子类的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。

  在 Java 中 synchronized 和在 lock、unlock 中操作保证原子性。

有序性:

  Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。

 volatile具备两种特性,第一就是保证共享变量对所有线程的可见性。将一个共享变量声明为volatile后,会有以下效应:

    1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的变量强制刷新到主内存中去;

    2.这个写会操作会导致其他线程中的缓存无效。

Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。

  在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比sychronized关键字更轻量级的同步机制。

  当对非 volatile 变量进行读写的时候,每个线程先从内存拷贝变量到CPU缓存中。如果计算机有多个CPU,每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝到不同的 CPU cache 中。

  而声明变量是 volatile 的,JVM 保证了每次读变量都从内存中读,跳过 CPU cache 这一步。

当一个变量定义为 volatile 之后,将具备两种特性:

  1.保证此变量对所有的线程的可见性,这里的“可见性”,如本文开头所述,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存来完成。

  2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障;(什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)。

volatile 性能:

  volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证

精进之路之volatile的更多相关文章

  1. python精进之路1---基础数据类型

    python精进之路1---基本数据类型 python的基本数据类型如上图,重点需要掌握字符串.列表和字典. 一.int.float类型 int主要是用于整数类型计算,float主要用于小数. int ...

  2. ❤️【Android精进之路-01】定计划,重行动来学Android吧❤️

    您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦. Android精进之路第一篇,确定安卓学习计划. 干货满满,建议收藏,需要用到时常看看.小伙伴们如有问题及需要,欢迎踊跃留言哦~ ~ ~. 前言 ...

  3. 《Go 精进之路》 读书笔记 (第一次更新)

    <Go 精进之路> 读书笔记.简要记录自己打五角星的部分,方便复习巩固.目前看到p120 Go 语言遵从的设计哲学为组合 垂直组合:类型嵌入,快速让一个类型复用其他类型已经实现的能力,实现 ...

  4. 精进之路之AQS及相关组件

    AQS ( AbstractQueuedSynchronizer)是一个用来构建锁和同步器的框架,使用AQS能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的ReentrantLock,Sem ...

  5. 精进之路之CAS

    CAS (Compare And Swap) 即比较交换, 是一种实现并发算法时常用到的技术,Java并发包中的很多类都使用了CAS技术,本文将深入的介绍CAS的原理. 其算法核心思想如下 执行函数: ...

  6. 精进之路之JMM

    JMM (Java Memory Model) java内存模型 Java内存模型的抽象 Java线程之间的通信由Java内存模型(本文简称为JMM)控制,JMM决定一个线程对共享变量的写入何时对另一 ...

  7. python精进之路 -- open函数

    下面是python中builtins文件里对open函数的定义,我将英文按照我的理解翻译成中文,方便以后查看. def open(file, mode='r', buffering=None, enc ...

  8. 精进之路之lru

    原理 LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”. 实现1 最常见的实现是 ...

  9. 精进之路之HashMap

    HashMap本质的核心就是“数组+链表”,数组对于访问速度很快,而链表的优势在于插入速度快,HashMap集二者于一身. 提到HashMap,我们不得不提各个版本对于HashMap的不同.本文中先从 ...

随机推荐

  1. restful接口定义的几种方式

    GET (SELECT): Retrieve a specific Resource from the Server, or a listing of Resources.        #从服务器检 ...

  2. 从mysql向HBase+Phoenix迁移数据的心得总结

    * 转载请注明出处 - yosql473 - 格物致知,经世致用 mysql -> HBase + Phoenix 1.总体方案有哪些? 1)通过Sqoop直接从服务器(JDBC方式)抽取数据到 ...

  3. Lab 10-1

    This lab includes both a driver and an executable. You can run the executable from anywhere, but in ...

  4. java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory的解决

    java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory的解决          博客分类: 问题 ApacheJavaTo ...

  5. CentOS6.5利用Docker部署ShowDoc

    在Docker中部署ShowDoc 一.安装Docker 1.安装Docker yum install docker 最后出现Complete即可 2.启动服务 # service docker st ...

  6. AndroidStudio中导入jar包的方法

    1.首先去下载需要的jar包 2.将jar包复制到project下的app->libs目录下(如果不存在libs目录新建一个) 3.右击该jar包,选择add as library,弹出窗口,点 ...

  7. mysql 压缩版配置

    1.解压之后可以将该文件夹改名,放到合适的位置,个人建议把文件夹改名为MySQL Server 5.6,放到C:\Program Files\MySQL路径中.当然你也可以放到自己想放的任意位置. 2 ...

  8. 【问题记录】使用FreeMarker生成数据,模板明明没错却一直报错“The following has evaluated to null or missing:”

    今天使用FreeMarker生成数据时一直报错,错误信息是“The following has evaluated to null or missing:”,告知我找不到值. 但是我再三确认,这些属性 ...

  9. There are multiple modules with names that only differ in casing. 黄色warning

    There are multiple modules with names that only differ in casing.有多个模块同名仅大小写不同This can lead to unexp ...

  10. ES5和ES6那些你必须知道的事儿(三)

    ES5和ES6那些你必须知道的事儿 ES6新增的东西 一.块级作用域:关键字let,常量const let与var的区别: a.不会进行变量声明提升 b.变量不允许被重复定义 c.变量不允许被删除 d ...