摘录

1、

  计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入。由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执行速度很快,而从内存读取数据和向内存写入数据的过程跟CPU执行指令的速度比起来要慢的多,因此如果任何时候对数据的操作都要通过和内存的交互来进行,会大大降低指令执行的速度。因此在CPU里面就有了高速缓存。也就是,当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。

  Java内存模型规定所有的变量(这里的变量指共享变量,存在线程间的访问竞争,包括实例字段、静态字段、构成数组的元素,但不包括局部变量与方法参数因为它们是线程私有的不会被共享)都是存在主存当中(类似于前面说的物理内存),每个线程都有自己的工作内存(类似于前面的高速缓存)。线程对变量的所有操作都必须在工作内存中进行,而不能直接对主存进行操作。并且每个线程不能访问其他线程的工作内存。

Java内存模型中的操作指令(8个,都是原子操作):lock、unlock、read、load、use、assign、store、write

Java内存模型与硬件内存模型的类比关系如下:

              vs     

2、

要想并发程序正确地执行,必须要保证原子性可见性(缓存一致性问题)以及有序性(指令重排序问题)。只要有一个没有被保证,就有可能会导致程序运行不正确。

  • 原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
  • 可见性:当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
  • 有序性:即程序执行的顺序按照代码的先后顺序执行。

3、

Java内存模型只保证了基本读取和赋值是原子性操作,如果要实现更大范围操作的原子性,可以通过synchronized和Lock来实现。

Java提供了volatile关键字来保证可见性。另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。

在Java里面,可以通过volatile关键字来保证一定的“有序性”,另外可以通过synchronized和Lock来保证有序性,此外,Java内存模型具备一些先天的“有序性”,即不需要通过任何手段就能够得到保证的有序性,这个通常也称为 happens-before 原则。

4、

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值(包括修改和写入主存两个操作,使用volatile关键字会强制将修改的值立即写入主存),这新值对其他线程来说是立即可见的(使其他线程的工作内存中该变量的值无效,从而重新从内存读取)。

2)禁止进行指令重排序。

volatile保证可见性和一定程度的有序性,但不保证原子性

不保证原子性的示例:

 class Test extends Thread {
static volatile int num = 0; public static void increament() {
num++;
} public static void main(String[] args) {
// TODO Auto-generated method stub
int loopCount = 10, increamentPerLoop = 1000;
long timeStart = System.currentTimeMillis();
for (int i = 0; i < loopCount; i++) {
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < increamentPerLoop; i++) {
increament();
}
}
}).start();
}
while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.printf("num:%d, time used:%dms\n", num, (System.currentTimeMillis() - timeStart));// num结果不是loopCount*increamentPerLoop,说明volatile没有确保原子性。其原因是虽然确保每次访问num得到的是最新的值,但num++不是原子操作,导致多线程并行时num的更新可能被覆盖
} }

volatile的原理和实现机制:

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

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

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

  2)它会强制将对缓存的修改操作立即写入主存;

  3)如果是写操作,它会导致其他CPU中对应的缓存行无效。

总结:

原子性:synchronized

可见性:volatile、synchronized、final

有序性:volatile、synchronized

参考资料

http://www.cnblogs.com/dolphin0520/p/3920373.html

《深入理解Java虚拟机》

 

Java 高效并发之volatile关键字解析的更多相关文章

  1. Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  2. (转)Java并发编程:volatile关键字解析

    转:http://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或 ...

  3. Java并发编程:volatile关键字解析(转载)

    转自https://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析   Java并发编程:volatile关键字解析 ...

  4. Java并发编程:volatile关键字解析-转

    Java并发编程:volatile关键字解析 转自海子:https://www.cnblogs.com/dayanjing/p/9954562.html volatile这个关键字可能很多朋友都听说过 ...

  5. Java并发编程:volatile关键字解析(学习总结-海子)

    博文地址:Java并发编程:volatile关键字解析

  6. 6、Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  7. 转:Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字, ...

  8. [转载]Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  9. 【转】Java并发编程:volatile关键字解析

    转自:http://www.importnew.com/18126.html#comment-487304 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备 ...

随机推荐

  1. 使用Method swizzling (也就是运行时交换两个方法的imp ,实现重写方法)

    贴上资源.很简单 https://gist.github.com/rudyjahchan/2191796 http://itony.me/592.html http://stackoverflow.c ...

  2. 2012版辅助开发工具包(ADT)新功能特性介绍及安装使用

    原文链接:http://android.eoe.cn/topic/android_sdk 2012年的Android辅助设备开发工具包(ADK)是Android开放设备协议(AOA)设备的最新参考实现 ...

  3. JAVA之堆内存和栈内存的差别

    欢迎转载.请附上出处: http://blog.csdn.net/as02446418/article/details/47007975 笔者近期在准备面试的时候又一次看了一些JAVA基础的知识,以下 ...

  4. 为jqgrid添加统计金额页脚

    为jqgrid增加自定义用户数据 设计统计的金额总和 最后在jgrid组件中添加 最后的效果为:

  5. 【Unity】第5章 3D坐标系和天空盒

    分类:Unity.C#.VS2015 创建日期:2016-04-20 一.简介 这一张主要介绍3D坐标系的基础知识以及各种形状的天空盒. 二.示例 本章的示例都在ch05Demos工程下.

  6. 【Android】1.0 第1章 C#之Android手机App开发

    分类:C#.Android.VS2015:创建日期:2016-01-20 目前Android在全世界市场上大约有75%的占有率,国人Android手机的持有比例更甚,甚至达到90%以上.因此搞计算机的 ...

  7. hdu Constructing Roads (最小生成树)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1102 /************************************************* ...

  8. CCObject

    /**************************************************************************** Copyright (c) 2010 coc ...

  9. windows远程连接mac配置方法

    1.开启mac共享服务,设置通过密码进行连接 [系统偏好设置]中选择[共享]打开[屏幕共享]服务,即可允许其他电脑的用户远程查看并控制此电脑.点击[电脑设置]配置访问密码 2. 下载TightVNC, ...

  10. IntelliJ IDEA 14.1.4破解方法-通过程序根据用户名生成注册码

    将下面的代码拷贝到Eclipse或者其他的开发工具中,在main方法中指定自己的用户名(随意),运行main方法,在控制台即可生成注册码.然后启动IntelliJ IDEA 14.1.4,然后根据提示 ...