volatile关键字相信大家都不陌生,在多线程并发编程里面用的比较多。网上有很多分析,但到底用和不用有什么区别,会造成什么影响,实际的代码示例比较少。现在就用代码来针对分析一下
引用linux之父Torvalds的一句话 -- talk is cheap show me the code
?
程序思路如下,先让thread2跑起来,进入一个循环,而这个循环也不是严格意义上的死循环,只不过解开死循环的key不在该线程本身,而是被另一个线程控制着。而这里的key有2个,一个是加了volatile,一个是没加,会有什么效果呢?运行下看看先(哇塞,用了句倒装)
?
class="java" name="code">package com.cug.thread; class VolatileExample { int x = 0; volatile int b = 0; private void write() { x = 5; b = 1; } private void read() { while (x != 5) { } /*while (b != 1) { }*/ } public static void main(String[] args) throws Exception { final VolatileExample example = new VolatileExample(); Thread thread1 = new Thread(new Runnable() { public void run() { try { //确保Thread2在Thread1之前执行 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } example.write(); } }); Thread thread2 = new Thread(new Runnable() { public void run() { example.read(); } }); thread2.start(); thread1.start(); } }
?
执行完了,大家会发现,当用x作为key的时候,不顶事儿,还是死循环。但用b作为key的时候,循环很快被解开,得到了我们预计的效果。
好了,有了实例,我们再带着问题好好分析。
?
首先我们需要简单说明一下java内存模型(java memory model)
根据Java Language Specification中的说明, jvm系统中存在一个主内存(Main Memory或Java Heap Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。
?
每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。
?
Java语言规范中也有指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才将私有拷贝与共享内存中的原始值进行比较。
?
通俗点说就是,这里的2个变量
int x = 0; volatile int b = 0;
x位于工作内存中,而b位于主存中。
再通俗点讲就是,thread1有一个自己的x,thread2有一个自己的x,而他们只有一个共享的b?
?
很多人拿volatile和synchronzed说事,比较效率啊什么的,其实这有什么好比的,两个人负责的功能点都不一样。有的地方可能确实可以用volatile代替synchronized,也确实能提升一些效率,但你有考虑过你代码的可读性吗?不要为了一时的效率,而牺牲别人对你代码意思的误解。(之前看过一个人写了个for循环,循环了50000次,问他干嘛这么写,他说他为了让程序在这稍微停一会)。
好了好了,不跑题,我们接着说
synchronized是同步的意思,同步代码块,同步函数等,意思就是让一小块独立成一个单元来执行。
?
而volatile呢,它的作用其实就是一个共享操作、集中管理的作用。不知道大家有没有看过火影,火影里面有一个Team很厉害叫佩恩(又快跑了。。),他是由6个人组成的,他有一个特殊点就是6个人可以交换视野,每个人都能看到另外5个人看到的东西。volatile扮演的就是这么一个视野的作用,共享属性,同步更新。对加了volatile关键字的属性,不会被加载到每个线程的工作内存中,而是在主存中修改查看
?
如有说的不好的不全的,大家可以到这里去看看,感觉这个还是很权威啊,我的只能叫小众,看合不合您的胃口了