volatile关键字的困惑

kunagfode 发布于 2013/08/21 16:44
阅读 239
收藏 0

下面两个java文件编译后,inAdd()方法的字节码是一样的,听说volatile关键字的作用是将变量同步到内存,让其他线程可见,但从字节码来看没有什么区别,不管属性定义成volatile还是非volatile,字节码指令都是通过getfield从运行时常量池取出字段值到java虚拟机数字操作栈,然后通过putfield将值存入运行时常量池,所以从java内存结构里找不到答案。这是为什么?求大神解惑。

public class Testvolatile
{
	public int index;
	public int inAdd()
	{
		return index++;
	}
}
public class  Testvolatile1{
     public volatile int index=0;
     public int inAdd(){
         return index++;
     }
}

以下是问题补充:

@kunagfode:为什么java虚拟机规范里面没有规定缓存类字段值的内存结构(它属于线程所有)?属于线程所有的内存结构只有一个java虚拟机栈,具体是属于一个方法的栈帧,栈帧包括操作数栈和局部变量表,这两个好像都不会缓存volatile字段。网上有人说java线程还有一块自己的私有内存用于缓存类变量。这里我不能理解 (2013/08/23 14:30)
加载中
0
袁不语
袁不语
1. 没看过字节码,也许public volatile int index;这行给了JVM必要的信息。
2. 用过hsdis打印出反汇编的代码看过。是会添加xchg和lock这样memory barrier指令的。可以参考我之前的 笔记
0
n
newlife867

inAdd 方法在字节码上是无区别的。都是

GETFIELD xxx.index

...(执行++)

PUTFIELD xxx.index

...(return)

但是index声明处的字节码是不一样的。

public 的access flags 是0x1。

public volatile 的access flags 是0x41。

所以JVM当inAdd方法执行到

GETFIELD xxx.index

PUTFIELD xxx.index

会根据access flags 的不同,解释成不同的机器指令序列。

这才是正真的被执行的二进制。

字节码理论上是被JVM解释执行的。(当然还有JIT技术,就不展开谈了)

更多关于JMM 可看文章

http://www.infoq.com/cn/articles/java-memory-model-4


n
newlife867
回复 @kunagfode : 按我的理解,一般所谓的某变量被缓存在java线程里,其实不是在jvm层面的说法,因为JVM规范压根没有规定哪些需要缓存,哪些不缓存。甚至jvm实现本身也不一定在实现线程的时候考虑过缓存变量什么的。所谓的缓存实际上是操作系统层面,甚或CPU层面的某些运作方式,在java层面看起来的现象。
k
kunagfode
为什么java虚拟机规范里面没有规定缓存类字段值的内存结构(它属于线程所有)?属于线程所有的内存结构只有一个java虚拟机栈,具体是属于一个方法的栈帧,栈帧包括操作数栈和局部变量表,这两个好像都不会缓存volatile字段。网上有人说java线程还有一块自己的私有内存用于缓存类变量。这里我不能理解
0
m
mononite

volatile的语义是没办法在字节码层次解释的,jdk 5支持新的内存模型jsr133没有添加新的字节码;volatile的语义是由jvm保障的,不管是解释执行还是jit。

另外,用synchronized修饰的方法,和没有synchronized修饰的方法,在字节码中的Code部分也是没区别的,javac并没有添加monitorenter和monitorexit指令,同步的逻辑也是由jvm在执行时来保证的。

0
k
kunagfode
谢谢各位大神了,受益了
返回顶部
顶部