volatile
修饰变量,直接存取原始内存的值;禁止指令重排序
volatile 百度百科
volatile可以保证内存的可见性
1.了解下线程内存和主内存的关系

如图,每个线程都有自己单独的内存空间,储存着从主内存拷贝进来的副本,如果变量是共享变量(多个线程会用到),那么就会存在线程A和线程B中变量A的值不相同的情况。
2.volatile强制直接从原始内存中存取
int a = 变量A
此时变量A会直接从主内存中加载
变量A++
此时变量A会直接写回主内存
public class VolatileTest {
//如果有volatile关键字程序会立即退出
//如果没有volatile关键字,程序可能永远不会退出
static volatile boolean isStop = false;
/*boolean isStop = false;*/
public void test() {
Thread t = new Thread() {
public void run() {
while (!isStop) ;
}
};
t.start();
}
public static void main(String args[]) throws InterruptedException {
for (int i = 0; i < 25; i++) {
new VolatileTest2().test();
}
isStop = true;
}
}
运行上面的代码看看结果
3.volatile能够保证有序性(禁止指令重排序)
在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
/**
* 一个简单的展示Happen-Before的例子.
* 这里有两个共享变量:a和flag,初始值分别为0和false.在ThreadA中先给a=1,然后flag=true.
* 如果按照有序的话,那么在ThreadB中如果if(flag)成功的话,则应该a=1,而a=a*1之后a仍然为1,下方的if(a==0)应该永远不会为真,永远不会打印.
* 但实际情况是:在试验100次的情况下会出现0次或几次的打印结果,而试验1000次结果更明显,有十几次打印.
*/
public class SimpleHappenBefore {
/** 这是一个验证结果的变量 */
private static int a=0;
/** 这是一个标志位 */
private static boolean flag=false;
public static void main(String[] args) throws InterruptedException {
//由于多线程情况下未必会试出重排序的结论,所以多试一些次
for(int i=0;i<1000;i++){
ThreadA threadA=new ThreadA();
ThreadB threadB=new ThreadB();
threadA.start();
threadB.start();
//这里等待线程结束后,重置共享变量,以使验证结果的工作变得简单些.
threadA.join();
threadB.join();
a=0;
flag=false;
}
}
static class ThreadA extends Thread{
public void run(){
a=1;
flag=true;
}
}
static class ThreadB extends Thread{
public void run(){
if(flag){
a=a*1;
}
if(a==0){
System.out.println("ha,a==0");
}
}
}
}
上段代码引用博客[http://my.oschina.net/004/blog/222069?fromerr=ER2mp62C]
网友评论