Java的内存模型(JMM)都是围绕着原子性,有序性,可见性。一些特殊的场合下,需要用volatile等关键字保证这些特性。
当用volatile声明一个变量时,就相当于告诉虚拟机,这个变量极有可能在多个线程中修改。为了确保这个变量被修改后,程序的所有线程都能够意识到这个改动,虚拟机就必须采用一些特殊的手段,保证这个变量的可见性。
声明的代码如下:
static volatile int i = 0;
注意:volatile虽然能很大程度的维护原子性,但是不能替代锁
一下一个简单的demo即可说明
public class volatileMain1 {
static volatile int i = 0;
public static class Task implements Runnable {
@Override
public void run(){
for(int k=0;k<10000;k++){
i++;//如果是原子性的,最终的是为100000(10个线程累计加10)
//实际是小于100000的
//证明volatile不能代替锁
}
}
public static void main(String[] args) throws InterruptedException {
Thread[] t = new Thread[10];
for(int i = 0;i<10;i++){
t[i] = new Thread(new Task());
t[i].start();
}
for(int i=0;i<10;i++){
t[i].join();
}
System.out.println(i);
}
}
}
实际的运行结果是小于100000的。。。
另外volatile也能保证数据的可见性和有序性,以后是一个简单的demo
public class volatileMain2 {
private static boolean ready;
private static String name;
private static class ReaderThread extends Thread{
@Override
public void run(){
while(!ready);//虚拟机在client模式下,由于JIT并没有做优化,主线程修改number,ReaderThread发现这个改动,退出程序
//虚拟机在server模式下,由于系统的优化,导致ReaderThread永远无法退出(因为readdy为false)
System.out.println("I am "+name);
}
}
public static void main(String[] args) throws InterruptedException {
new ReaderThread().start();
Thread.sleep(1000);
name = "yemt";
ready = true;
Thread.sleep(10000);
}
}
注意:可以使用Java虚拟机参数-server切换到Server模式