Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。

这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。

在JDK1.2之前,Java的内存模型实现总是从主存(即共享内存)读取变量,是不需要进行特别的注意的。而随着JVM的成熟和优化,现在在多线程环境下volatile关键字的使用变得非常重要。

在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。
要解决这个问题,就需要把变量声明为volatile(也可以使用同步,参见http://blog.csdn.net/ns_code/article/details/17288243),这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说来,多任务环境下,各任务间共享的变量都应该加volatile修饰符。
Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才将私有拷贝与共享内存中的原始值进行比较。
这样当多个线程同时与某个对象交互时,就必须注意到要让线程及时的得到共享成员变量的变化。而volatile关键字就是提示JVM:对于这个成员变量,不能保存它的私有拷贝,而应直接与共享成员变量交互。
volatile是一种稍弱的同步机制,在访问volatile变量时不会执行加锁操作,也就不会执行线程阻塞,因此volatilei变量是一种比synchronized关键字更轻量级的同步机制。
使用建议:
在两个或者更多的线程需要访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,没必要使用volatile。
由于使用volatile屏蔽掉了JVM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字

要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:

  • 对变量的写操作不依赖于当前值。
  • 该变量没有包含在具有其他变量的不变式中。
package com.subject01;

public class VolatileDemo extends Object implements Runnable {
//value变量没有被标记为volatile
private int value;
//missedIt变量被标记为volatile
private volatile boolean missedIt;
//creationTime不需要声明为volatile,因为代码执行中它没有发生变化
private long creationTime; public VolatileDemo() {
value = 10;
missedIt = false;
//获取当前时间,亦即调用Volatile构造函数时的时间
creationTime = System.currentTimeMillis();
} public void run() {
print("entering run()"); //循环检查value的值是否不同
while ( value < 20 ) {
//如果missedIt的值被修改为true,则通过break退出循环
if ( missedIt ) {
//进入同步代码块前,将value的值赋给currValue
int currValue = value;
//在一个任意对象上执行同步语句,目的是为了让该线程在进入和离开同步代码块时,
//将该线程中的所有变量的私有拷贝与共享内存中的原始值进行比较,
//从而发现没有用volatile标记的变量所发生的变化
Object lock = new Object();
synchronized ( lock ) {
//不做任何事
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//离开同步代码块后,将此时value的值赋给valueAfterSync
int valueAfterSync = value;
print("in run() - see value=" + currValue +", but rumor has it that it changed!");
print("in run() - valueAfterSync=" + valueAfterSync);
break;
}
}
print("leaving run()");
} public void workMethod() throws InterruptedException {
print("entering workMethod()");
print("in workMethod() - about to sleep for 2 seconds");
Thread.sleep(2000);
//仅在此改变missedIt的值
missedIt = true;
print("in workMethod() - just set missedIt=" + missedIt);
print("in workMethod() - about to sleep for 3 seconds");
// Thread.sleep(5000);
//仅在此改变value的值
value = 50;
print("in workMethod() - just set value=" + value);
print("in workMethod() - about to sleep for 5 seconds"); Thread.sleep(3000);
print("leaving workMethod()");
} /*
*该方法的功能是在要打印的msg信息前打印出程序执行到此所化去的时间,以及打印msg的代码所在的线程
*/
private void print(String msg) {
//使用java.text包的功能,可以简化这个方法,但是这里没有利用这一点
long interval = System.currentTimeMillis() - creationTime;
String tmpStr = " " + ( interval / 1000.0 ) + "000";
int pos = tmpStr.indexOf(".");
String secStr = tmpStr.substring(pos - 2, pos + 4);
String nameStr = " " + Thread.currentThread().getName();
nameStr = nameStr.substring(nameStr.length() - 8, nameStr.length());
System.out.println(secStr + " " + nameStr + ": " + msg);
} public static void main(String[] args) {
try {
//通过该构造函数可以获取实时时钟的当前时间
VolatileDemo vol = new VolatileDemo(); //稍停100ms,以让实时时钟稍稍超前获取时间,使print()中创建的消息打印的时间值大于0
Thread.sleep(100); Thread t = new Thread(vol);
t.start(); //休眠100ms,让刚刚启动的线程有时间运行
Thread.sleep(100);
//workMethod方法在main线程中运行
vol.workMethod();
} catch ( InterruptedException x ) {
System.err.println("one of the sleeps was interrupted");
}
}
}

  参考的帖子及文章

http://blog.csdn.net/ns_code/article/details/17101369

http://www.ibm.com/developerworks/cn/java/j-jtp06197.html  (写的相当的好)

JAVA 并发实现六(Volatile的使用)的更多相关文章

  1. Java并发(六):volatile的实现原理

    synchronized是一个重量级的锁,volatile通常被比喻成轻量级的synchronized volatile是一个变量修饰符,只能用来修饰变量. volatile写:当写一个volatil ...

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

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

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

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

  4. 【死磕Java并发】-----深入分析volatile的实现原理

      通过前面一章我们了解了synchronized是一个重量级的锁,虽然JVM对它做了很多优化,而下面介绍的volatile则是轻量级的synchronized.如果一个变量使用volatile,则它 ...

  5. Java 并发编程:volatile的使用及其原理

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

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

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

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

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

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

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

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

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

随机推荐

  1. 百度背景画面切换效果,js做

    <!DOCTYPE html><html><head> <title>baidu</title> <meta charset=&quo ...

  2. 如何使用CSS Sprites技术进行图片合并

    http://jingyan.baidu.com/article/066074d6757654c3c21cb02d.html

  3. c - 统计字符串"字母,空格,数字,其他字符"的个数和行数.

    #include <stdio.h> #include <ctype.h> using namespace std; /* 题目:输入一行字符,分别统计出其中英文字母.空格.数 ...

  4. oracle单行函数之字符函数

    Lower--转换为小写 upper--转换为大写 Initcap--首字母大写 concat--连接字符 substr--截取字符 length/length--获取字符串长度(字节长度) inst ...

  5. 武汉科技大学ACM :1003: A+B for Input-Output Practice (III)

    Problem Description Your task is to Calculate a + b. Input Input contains multiple test cases. Each ...

  6. querySelector选择器

    querySelector选择器可以通过document和element来调用他们 用来代替getElementById var body=document.querySelector("b ...

  7. ajax提交表单序列化(serialize())数据

    知识点: $("#form").serialize();将表单数据序列化为标准URL编码文本字符串(key1=value1&key2=value2…). 以下用一个例子来演 ...

  8. [转载] 关于“淘宝应对"双11"的技术架构分析”

    微博上一篇最新的关于“淘宝应对"双11"的技术架构分析”.数据产品的一个最大特点是数据的非实时写入.

  9. 流Stream个人学习理解

    1.Stream类 命名空间:System.IO 程序集:mscorlib 流是对字节序列的抽象,提供字节序列的一般视图. 流的操作包括三个方面: 1.读取(Read):将流数据传入到数据结构 2.写 ...

  10. python 多层装饰器

    25.多层装饰器:      1.原理:执行顺序从上往下,#2和#3组成一个函数假设为nf1,#1和nf1组成一个函数nnf1           f1成为ck_ty_of_us的inner函数即nf ...