- 浏览: 468879 次
- 性别:
- 来自: 天巢
文章分类
最新评论
-
ron.luo:
哥们你的一句话点醒了我,Very Good !
log4j:WARN Please initialize the log4j system properly解决办法 -
zdjray:
<div class="quote_title ...
Java中的Volatile关键字详解 -
u012075079:
谢谢楼至,ubuntu乱码解决了,在ubuntu13.10下稍 ...
Netbeans中文乱码问题汇总 -
卖火柴的小法海:
中文乱码怎么解决呢,显示中文是个四方块的东西
Java Web模块——验证码模块 -
cciiu:
谢谢
Java Web模块——验证码模块
前两天,并行实验室发表了一篇有关volatile关键字的文章[1],而该文参考文献中的Sayonara volatile[2]则更直接地要与volatile再见。两篇文章不谋而合,从c/c++到Java/.net,将这几门语言中的volatile过了一遍。列举出各种乱象,看上去volatile是如此不堪。 确实,volatile的语义不是那么常见。不是锁,但是它又拥有锁的部分特性(可见性,Java 5以后还有顺序保证)。如果不能正确理解,确实是个容易出错的地方。但是如果理解了用对了,仅就Java 5以及以后的版本而言,在目前阶段,volatile对性能上的提升还是有帮助的。 在维基百科上,对Java中的Volatile给了一个准确的定义[6]: 翻译过来就是: 在Java中,要正确地并发,必须在原子性、可见性和顺序性三个方面做出保证。在Java 5以前的版本中,volatile就已经实现了可见性,但是因为不能保证与普通变量读写之间的顺序,故而经常是没有用的。在Java 5以后的版本中,则额外保证了其与普通变量读写的顺序性。这里不是特别好懂,我们将javamx上的例子[3] [4]改造一下: 上面的代码,在Java5以前,这个例子是不能正确工作的,因为volatile不保证对field1,field2的初始化(常规读写)一定在对volatile变量instance的写之前完成。但双检查锁本身并非volatile导致的,反而是Java 1.5的volatile让双检查锁能正确工作了。并行实验室将双检查锁不正确算在volatile的头上,有点冤了。 正是因为volatile在Java 5以前没有得到正确实现,更添加了不少复杂性。在Java 5之前,volatile基本没用处。 在Hotspot JVM中, 这与synchronized是有明显不同的,synchronized通常需要原子锁定,在SMP上要通过锁定总线等方式来实现,其代价在大多数平台上通常要比volatile高得多。 简单写了一个测试来比较一下volatile以及它的两种替代品 — 原子类型(atomic)和锁(此处指synchronized)。例子的代码改编自庄周梦蝶的slides《Java NIO trick and trap》中的SystemTimer(部分代码省略,完整源码在Github上)。这个测试只是一个例子,但其实在网络库里都要做定时,原理也大抵如此。 第一个版本如下: 代码的重点在于volatile修饰的time域。time是一个只有一个线程写,其他线程都是读的域,没有并发修改,这里要解决的就是可见性。这正是volatile最适合的场合。 第二个版本使用synchronize关键字,与版本V1的不同如下: 第二个版本使用Java的内部锁来同步,既保证了原子性,也保证了可见性。第三个版本则是使用AtomicLong来实现的,如下: 在我的本上(cpu: 2core; OS: win7/cygwin; java:1.6.0_13)运行100万次,其性能如上面右图一所示(单位:ms)。 结论:性能上的优越性是显而易见的。volatile比AtomicLong明细要快,相比于synchronized则有几倍几十倍的提高了。 [Update, Dec15th: 图片是用Google Chart API 生成的,在源代码中包含着两个自动执行测试并生成图片URL的脚本。脚本需运行在Bash环境下,Windows上需在Cygwin下运行。] 写博文时顺便统计了下volatile在一些性能比较重要的程序中的情况,我顺手统计了手边有的mina和netty两个项目的核心代码,数据如下: 其中,mina是2009-3-31日Subversion的trunk,如下: netty的版本信息是: 从侧面证明了volatile其实是很重要的,在性能很重要的场合,应用还是比较多的。 总而言之,相比与Atomic和synchronized,volatile在性能上还是有显著的优势。 不过,正如文章中开头讨论的那样,volatile的缺点也显而易见,需要开发者对volatile的应用需要对内存模型的理解,否则容易误解而造成错误。在并发程序中,其仅可用于JVM支持的几个基本类型(int,short,long,double,reference, etc.),而这几个基本类型皆有对应的完整并发特性的包装原子类型(java.util.concurrent.atomic.*),虽然其性能与volatile有些差距,但大部分情形下也可代替volatile(但用synchronized来代替volatile是很不划算的)。Volatile在Java中的语义以及历史
public class MyBrokenFactory {
private static volatile MyFactory instance;
private int field1, field2 ...
public static MyBrokenFactory getFactory() {
// This is incorrect: don't do it at home, kids!
if (instance == null) {
synchronized (MyBrokenFactory.class) {
if (instance == null)
instance = new MyBrokenFactory();
}
}
return instance;
}
private MyBrokenFactory() {
field1 = ...
field2 = ...
}
}
Volatile的实现机制分析
a) 在JVM层次,对volatile变量在线程本地工作区中不做缓存,对volatile的读写总是指向堆中的引用。可以视作在一个assign指令后总是跟着一个store指令[5]。
b) 在机器码执行层次,通过内存屏障指令等迫使CPU不重排序,清除缓存,详细请参考《Memory Barriers and JVM Concurrency》的分析。Performance
引入Volatile的主要目的,就是为了性能。我分下面几个方面来谈谈volatile在目前的Java平台中的作用。直接性能比较
package me.xiping.volitileverify;
public class SystemTimerV1 {
private final static ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private static final long tickUnit = Long.parseLong(System.getProperty(
"notify.systimer.tick", "50"));
private static volatile long time = System.currentTimeMillis();
private static class TimerTicker implements Runnable {
public void run() {
time = System.currentTimeMillis();
}
}
public static long currentTimeMillis() {
return time;
}
static {
executor.scheduleAtFixedRate(new TimerTicker(), tickUnit, tickUnit,
TimeUnit.MILLISECONDS);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
executor.shutdown();
}
});
}
}
package me.xiping.volitileverify;
public class SystemTimerV2 {
....
private static long time = System.currentTimeMillis();
private static class TimerTicker implements Runnable {
public void run() {
synchronized (SystemTimerV2.class) {
time = System.currentTimeMillis();
}
}
}
public static synchronized long currentTimeMillis() {
return time;
}
....
}
package me.xiping.volitileverify;
public class SystemTimerV3 {
......
private static AtomicLong time = new AtomicLong(System.currentTimeMillis());
private static class TimerTicker implements Runnable {
public void run() {
time.set(System.currentTimeMillis());
}
}
public static long currentTimeMillis() {
return time.get();
}
.....
}
运行1000万次性能如图二所示(注意纵坐标的值与图一不一样)。
(欢迎在不同平台下测试并在评论中给一个反馈,反馈时请包括处理器信息(平台,core数),OS和Java版本。源代码在这里。编译和运行需要Ant,具体指南请参考这里。)Mina/netty对volatile的利用
Project
sources path
synchronized occurrence
volatile occurrence
netty
src/main/java
150
177
mina
src/main/java
216
55
$svn info
Path: .
URL: http://svn.apache.org/repos/asf/mina/trunk
Repository Root: http://svn.apache.org/repos/asf
Repository UUID: 13f79535-47bb-0310-9956-ffa450edef68
Revision: 761900
Node Kind: directory
Schedule: normal
Last Changed Author: jvermillard
Last Changed Rev: 760493
Last Changed Date: 2009-03-31 23:49:15 +0800 (Tue, 31 Mar 2009)
$git log
commit 1ffb1aea75c36def56b709bd0892b19df78d9249
Author: Trustin Lee <trustin@gmail.com>
Date: Fri Nov 12 10:20:03 2010 +0900
结论
评论
synchronized (MyBrokenFactory.class) {
if (instance == null)
instance = new MyBrokenFactory();
}
}
如果instance不是volatile类型的,会出现创建多个的情况么?
不会,但是可能会返回一个错误的实例状态,这时还没有进synchronized就返回了
synchronized (MyBrokenFactory.class) {
if (instance == null)
instance = new MyBrokenFactory();
}
}
如果instance不是volatile类型的,会出现创建多个的情况么?
发表评论
-
关于 display: inline 、block 、inline-block
2012-05-19 21:07 187block元素的特点是:总是在新行上开始;高度,行高以及 ... -
使用javascript来互相转换画布canvas和图片image
2012-05-19 19:57 19031.使用javascript的drawImage方法可以方便的 ... -
理解HTML5 canvas.translate(x,y)
2012-05-09 00:52 3427规范原文如下:The translate(x, y) meth ... -
CSS3–transform 变形金刚
2012-05-08 20:17 1821原文地址:http://missdo ... -
meta
2012-05-06 14:39 1183meta是用来在HTML文档中模拟HTTP协议的响应头 ... -
使用jQuery创建人性化的返回顶部链接
2012-05-06 13:19 1481一、HTML(基本结构) -
兼容IE,Firefox,Chrome等浏览器 : 设为首页和加入收藏夹的Javascript代码
2012-04-28 21:51 6326由于chrome,safari,opara 浏览器还未支 ... -
JFreeChart的使用
2012-04-27 20:33 1262WWW 的发展使得基于因特网的应用程序不再局限于静态或者简单的 ... -
详解struts2中struts.properties
2012-04-25 10:36 1311struts.xml和struts.prope ... -
Unable to find parent packages json-default的解决办法
2012-04-24 16:45 3293Unable to find parent packages ... -
log4j:WARN Please initialize the log4j system properly解决办法
2012-04-23 09:57 242815log4j:WARN No appenders coul ... -
pear安装图文详解
2012-04-16 20:32 1597这是PHP性能优化系列第一期,如何在Windows环境下安装P ... -
教你如何安装PEAR 本文来源网页吧http://www.wangyeba.com
2012-04-16 20:16 1410pear是PHP的扩展和应用程序库,包含了很多有用的类, ... -
PHP引用符&的用法介绍
2012-04-15 22:51 1134关于php的引用(就是在变量或者函数、对象等前面加上&a ... -
文档模式
2012-03-16 16:10 11872.2 文档模式IE5.5引入了文档模式的概念,而这个概念是通 ... -
Command命令大全
2012-01-18 21:31 1520windows CMD 快捷命令大全 (保存着,对您以后肯定有 ... -
虚拟内存 & RamDisk 的详细 使用教程&建议(解决4G利用率问题)
2012-01-13 23:02 2224内存盘(RamDisk)简称“RM盘”可以 ... -
RAMDISK 4G的用法
2012-01-13 23:00 1906现在内存已经是无敌大白菜价了,在怎么垃圾的配置的朋友也都玩上4 ... -
定制xcode开发环境
2011-12-09 17:46 6716一、下载安装Xcode4 因为我需要让Xcode ... -
xcode常用快捷键
2011-12-09 12:41 17361. 文件CMD + N: 新文件CMD + SHIFT ...
相关推荐
"Java中的Volatile关键字详解" Java中的Volatile关键字详解是Java中的一种关键字,用于保证线程之间的可见性、原子性和有序性。下面是对Java中的Volatile关键字详解的知识点总结: 一、基本概念 1. 可见性:可见...
Java中Volatile关键字详解及代码示例 一、基本概念 在Java中,Volatile关键字是一个非常重要的概念,它与Java内存模型中的可见性、原子性和有序性息息相关。可见性是指线程之间的可见性,一个线程修改的状态对另一...
java里的volatile关键字详解.pdf
volatile
Java多线程volatile关键字详解 Java多线程volatile关键字详解主要介绍了Java多线程volatile关键字的应用和原理。volatile是一种轻量同步机制,可以确保变量的可见性和顺序性,但不保证原子性。 volatile关键字的...
Java中的`volatile`关键字是一个非常重要的并发控制工具,它提供了比`synchronized`关键字更为轻量级的同步机制。`volatile`关键字的主要作用是确保多线程环境下的可见性和禁止指令重排序,但不保证原子性。 **...
Java 线程 volatile 关键字详解 Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。volatile 变量的同步性较差,但它有时更简单并且开销更低。volatile 变量可以被看作是一种 “程度较轻的 ...
Java并发教程之volatile关键字详解 Java并发教程之volatile关键字的相关资料,对大家学习或者使用Java具有一定的参考学习价值。在Java中,volatile关键字是解决多线程问题的重要工具。本文将会详细介绍volatile...
Java中的`volatile`关键字是一个非常重要的并发编程工具,它的作用主要体现在两个方面:**可见性**和**有序性**。本文将深入解析`volatile`的关键字特性及其在实际编程中的应用。 1. 可见性: 当一个共享变量被`...
"Java面试官最爱问的volatile关键字详解" Java面试官最爱问的volatile关键字是Java并发编程中一个重要的概念,了解volatile关键字可以帮助开发者更好地理解Java内存模型(JMM)和Java并发编程的特性。本文将详细...
在Java中,volatile关键字经常用来修饰变量。volatile关键字的作用是使变量在多个线程之间可见。volatile关键字可以保证变量的可见性,但不能保证变量的原子性。 在Java虚拟机(JVM)中,每个线程都有自己的线程栈...
Java Volatile关键字同步机制详解 Java Volatile关键字是Java语言中的一种同步机制,它可以保证在多线程环境下变量的可见性和原子性。通过使用Volatile关键字,可以确保在多线程环境下对变量的修改是可见的,并且...
Java编程语言中有51个关键字,它们在程序中扮演着至关重要的角色,用来定义类、接口、变量、方法以及控制程序流程。以下是一些主要的关键字及其解释: 1. `abstract`:抽象关键字,用于声明抽象类和抽象方法。抽象...
### Java中的关键字大全 在Java编程语言中,关键字是一组预定义的词汇,它们具有特殊的含义和用途。理解和掌握这些关键字对于编写有效的Java程序至关重要。本文将详细介绍Java中的一些核心关键字,并提供相应的解释...
《面试官最爱的volatile关键字详解》 在Java编程中,volatile关键字是一个至关重要的概念,尤其在多线程环境下,理解并正确使用volatile是面试时必不可少的知识点。volatile被视为synchronized的一种轻量级实现,但...
Java中的`volatile`关键字是多线程编程中一个非常重要的概念,它用于修饰变量,确保在并发环境下,多个线程可以正确地共享和同步数据。本文将深入探讨`volatile`关键字的工作原理、特性以及如何使用它来解决多线程中...
### Java中的transient关键字详解 在Java编程语言中,`transient`关键字是一个非常重要的概念,主要用于对象序列化过程中对特定变量的控制。当一个类实现了`Serializable`接口时,其对象可以被序列化为一个持久化的...
23. `volatile`:`volatile`关键字保证了变量在多线程环境中的可见性和一致性,避免了缓存导致的数据不一致问题。 24. `while`:`while`循环在满足条件时重复执行代码块,语法为`while (condition) { statements }`...
Java中的`volatile`关键字是一个非常重要的并发编程工具,它的主要作用是确保共享变量在多线程环境下的可见性和有序性。下面将详细解释`volatile`的关键特性、它如何解决并发问题以及相关的`happens-before`原则。 ...