什么是volatile

Java语言允许线程访问共享变量,为了确保共享变量能够被准确一致地更新,如果一个字段被声明为volatile,那么Java内存模型将会确保所有线程看到这个变量时值是一致的。保证了多处理器开发中,共享变量的可见性。

volatile的使用

public volatile int num;

volatile的实现原理

由volatile修饰的共享变量进行写操作的时候,汇编代码中会多出一些操作,这些操作包括:

  • 将当前处理器缓存的数据写回到系统内存。
  • 这个写回的操作会使得其他处理器缓存的该内存地址无效。

volatile的特性

可见性

什么是可见性

内存可见性是指:一个线程修改一个变量的值后,其他的线程在访问这个变量的时候,就会立即得到修改后的值。即,一个线程对一条共享变量的修改,对其他线程可见。

如果没有采用同步机制,那么共享变量对其他线程不会立即可见

为什么会出现内存不可见的情况

因为线程对变量有本地缓存,当开启线程的时候,系统会将共享内存中的数据拷贝到本地缓存,在线程结束前所有的操作都是基于本地缓存进行的,如果一个线程改变了一个共享变量,而其他线程本地缓存没有及时得到更新,操作的还是旧的值。

这时候就需要同步机制来将修改的值同步到每个线程的本地缓存。

如何确保共享变量的可见性

对共享变量使用同步机制,在Java中可以:

  • 将共享变量用同步代码块包裹。
  • 用volatile修饰变量。

为什么volatile可以保持共享变量的可见性

用volatile修饰后的变量,在读写的时候,就多了一些操作:

  • 变量写:这个变量会直接写入共享内存,而不是线程的本地缓存空间。
  • 变量读:线程会从共享内存中读取这个变量,而不是从本地的缓存空间中读。

volatile的额外功能

当volatile变量进行写的时候,系统会将包括被修改的变量在内的所有线程本地缓存变量存到系统共享内存中。
当volatile变量进行读的时候,系统也会将共享内存中所有的变量更新到线程的本地缓存。

这就意味着,其他的普通变量在volatile变量之前被修改,那么,volatile变量被修改之后,这些变量也能被其他线程读到最新的值。

原子性

什么是原子性

原子性是指一组操作连续地完成,中间不会被其他线程任务中断。

volatile能确保long、double等8子节数据操作地原子性

在32位的操作系统中,CPU一次只能读写32位的数据,由于long和double是64位的,所以它们的读写会进行两步。如果在多线程中,一个线程只操作了long、double的前面一部分,然后突然就有另一个线程进来操作这个变量,那么,得到的数据就是错的。

可以利用volatile防止上述情况的发生,即操作long等数据的原子性。

Java怎么实现原子操作

使用循环CAS实现原子操作,基本思路就是循环进行CAS操作直到成功为止。1.5开始提供基本类的源自类。

CAS操作的问题:

  1. ABA问题:虽然两次比较变量是相同的,但可能在中间时刻被修改成其他的值,又改回原值,这样就不能被知晓。在每次修改变量的时候追加版本号,CAS的时候一起比较版本号即可。
  2. 循环时间开销大:支持处理器提供的pause指令以提高执行效率。
  3. 只能保证一个共享变量的原子操作:可以把多个变量合并对比。

重排序相关

重排序是计算机系统为了提高程序的执行效率,改变代码执行顺序的一种行为。

如果两个指令没有依赖关系,系统会对它们的顺序重新排序,但是如果变量被volatile修饰,那么重排序规则会相应发生变化:

  • volatile读:volatile变量的读操作前一行为volatile操作,那么这两行不会发生重排序;volatile读操作和它后一行代码不会发生重排序。
  • volatile写:volatile写操作与其前一行代码不会发生重排序;volatile写操作的后一行代码是volatile操作,那么这两行代码不会发生重排序。

为什么需要这样的重排序规则呢?

我认为是利用这个规则,实现进程间的通信。看下面这段代码:

class VolatileExample {
int a = 0;
volatile boolean flag = false;
public void write() {
a = 1;
flag = true;
} public void read() {
if(flag) {
int i = a;
...
}
}
}

线程A执行write之后,线程B执行read就能获得i被传递的值。就是应为在volatile读之前的数据不能跑到volatile后面,如果跑过去了,那想要传递的值就是看不见了。

Java并发编程的艺术(二)——volatile、原子性的更多相关文章

  1. Java并发编程的艺术(三)——volatile

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

  2. Java并发编程的艺术(二)——重排序

    当我们写一个单线程程序时,总以为计算机会一行行地运行代码,然而事实并非如此. 什么是重排序? 重排序指的是编译器.处理器在不改变程序执行结果的前提下,重新排列指令的执行顺序,以达到最佳的运行效率. 重 ...

  3. Java并发编程的艺术(六)——线程间的通信

    多条线程之间有时需要数据交互,下面介绍五种线程间数据交互的方式,他们的使用场景各有不同. 1. volatile.synchronized关键字 PS:关于volatile的详细介绍请移步至:Java ...

  4. 《Java并发编程的艺术》读书笔记:二、Java并发机制的底层实现原理

    二.Java并发机制底层实现原理 这里是我的<Java并发编程的艺术>读书笔记的第二篇,对前文有兴趣的朋友可以去这里看第一篇:一.并发编程的目的与挑战 有兴趣讨论的朋友可以给我留言! 1. ...

  5. 读书笔记之《Java 并发编程的艺术》

    一.多线程语义 即使是单核处理器也支持多线程执行代码,CPU 通过给每个线程分配 CPU 时间片来执行任务,当前任务执行一个时间片后会切换到下一个任务,所以 CPU 通过不停的切换线程执行. 并发执行 ...

  6. Java并发编程底层实现原理 - volatile

    Java语言规范第三版中对volatile的定义如下: Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致性的更新,线程应该确保通过排他锁 单独获得这个变量. volatile有时候 ...

  7. 读《Java并发编程的艺术》(一)

    离开博客园很久了,自从找到工作,到现在基本没有再写过博客了.在大学培养起来的写博客的习惯在慢慢的消失殆尽,感觉汗颜.所以现在要开始重新培养起这个习惯,定期写博客不仅是对自己学习知识的一种沉淀,更是在督 ...

  8. Java并发编程的艺术读书笔记(2)-并发编程模型

    title: Java并发编程的艺术读书笔记(2)-并发编程模型 date: 2017-05-05 23:37:20 tags: ['多线程','并发'] categories: 读书笔记 --- 1 ...

  9. 《Java并发编程的艺术》留给自己以后看的笔记

    <Java并发编程的艺术>这本书特别好,和<深入了解JAVA虚拟机>有一拼,建议做java的都看看,下面全部都是复制书中的部分内容,主要目的是做个笔记,方便以后遇到问题能找到. ...

  10. Java并发编程的艺术读书笔记(1)-并发编程的挑战

    title: Java并发编程的艺术读书笔记(1)-并发编程的挑战 date: 2017-05-03 23:28:45 tags: ['多线程','并发'] categories: 读书笔记 --- ...

随机推荐

  1. ip rule 策略路由

    1. 工具安装 yum install iproute 查看工具是否安装 ip -V 2. ip rule 和 ip route ip命令中和策略路由相关的OBJECT有 rule 和 route. ...

  2. centos6安装calamari

    安装操作系统 首先安装操作系统centos6,安装过程选择的是base server,这个不相同不要紧,出现缺少包的时候去iso找出来安装就可以了 calamari的简单介绍 首先简单的介绍下cala ...

  3. oracle 11.2.0.4静默安装

    oracle 11.2.0.4静默安装 1.安装包 1.1.上传安装包 xshell可用rz命令,选择安装包. mobaxterm可用左侧栏上传功能. 2.安装准备 2.1.关闭防火墙.SELinux ...

  4. bWAPP----HTML Injection - Reflected (POST)

    bWAPP--low--HTML Injection - Reflected (POST) 只不过是把传递方式换成post, 防护的三个级别和内容与GET相同 1 function htmli($da ...

  5. 百度ping工具

    function postUrl($url, $postvar) { $ch = curl_init(); $headers = array( "POST".$url." ...

  6. 面试官:小伙子,说一说Java多线程有哪些创建方式吧

    第一种 继承Thread类 自定义类,继承Thread类,并重写run()方法. class MyThread1 extends Thread { @Override public void run( ...

  7. .Net orm 开源项目 FreeSql 2.0.0(满意的答卷)

    写在开头 2018年11月头脑发热到今天,一晃已经两年,当初从舒服区走向一个巨大的坑,回头一看后背一凉. 两年时间从无到有,经历数不清的日夜奋斗(有人问花了多长时间投入,答案:全职x2 + 两年无休息 ...

  8. 如何在Mac上安全彻底的卸载软件?

    Mac如何卸载软件呢?通常我们的做法都是将应用程序图标移动到废纸篓中,这样就算是将mac软件卸载了,但是这样真的将软件卸载干净了吗?当然没有,一个软件并不是只有应用程序包,他还会包含很多的偏好文件等等 ...

  9. Java之 函数(五)

    第一部分 : IDEA开发工具 1.数组 1.1 数组介绍 ​ 数组就是存储数据长度固定的容器,存储多个数据的数据类型要一致. 1.2 数组的定义格式 1.2.1 第一种格式 ​ 数据类型[] 数组名 ...

  10. 2017年第八届蓝桥杯【C++省赛B组】B、C、D、H 题解

    可能因为我使用暴力思维比较少,这场感觉难度不低. B. 等差素数列 #暴力 #枚举 题意 类似:\(7,37,67,97,127,157\) 这样完全由素数组成的等差数列,叫等差素数数列. 上边的数列 ...