在讲解之前先来看一个例子
package org.MyVolatile;
public class MyVolatile {
public static void main(String[] args) {
// TODO Auto-generated method stub
TestVolatile testVolatile = new TestVolatile();
testVolatile.start();
try {
Thread.sleep(100);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println("主线程设置flag为false");
testVolatile.setFlag(false);
}
}
class TestVolatile extends Thread{
private boolean flag = true;
@Override
public void run() {
System.out.println("执行线程");
while(true) {
if(!flag) {
break;
}
}
System.out.println("退出线程");
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
线程执行体中当flag设置为false时,线程便会结束执行.
在主线程里将flag设置为false.但是结果却令人意外.
输出
执行线程
主线程设置flag为false
也就是说线程中的循环并没有结束执行,还在运行.
解决
使用volatile 修饰flag.
volatile private boolean flag = true;
重新执行
输出
执行线程
主线程设置flag为false
退出线程
也就是加了volatile后,程序终于按照我们所想的逻辑实现了.
原因
JVM在创建每一个线程时,都会给该线程创建一个私有堆栈,造成上述问题的原因是私有堆栈中的值和公有堆栈中的值不同步造成的.解决这个问题就需要使用volatile.当线程访问被volatile修饰的变量时,会强制从公有堆栈中获取值.
synchronized和volatile比较
1.关键字volatile是线程同步的轻量级表现,所以volatile的性能肯定比synchronized要好.
2.volatile只能修饰变量,而synchronized可以修饰方法和语句块.
3.多线程访问volatile变量不会发生阻塞,但是访问synchronized修饰的方法和语句块会发生阻塞.
4.volatile只能保证多线程间数据的可见性,并不能保证原子性与安全性.
而synchronized可以保证原子性,可见性,安全性.
5.volatile解决的是多线程间的可见性,而synchronized解决的是多线程之间访问资源的同步性.