Java高并发学习(二)
volatile与java内存模型(JMM)
Java的内存模型都是围绕着原子性,有序性和可见性展开的。为了在适当的场合,确保线程间的原子性,有序性,可见性。Java使用了一些特殊的操作或者关键字来声明,告诉虚拟机,在这个地方,要尤其注意,不能随意的优化目标指令。关键字volatile就是其中之一。
当你用volatile来声明一个变量时,就等于告诉了虚拟机,这个变量极有可能会被某些程序或者是线程修改。为了确保这个变量被修改后,应用程序范围内所有线程都能看到这个改动,虚拟机就必须采取一些特殊的手段,保证这个变量的可见性等特点。
此外,volatile也能保证数据的可见性和有序性。下面来看一个简单的例子:
import java.util.Objects;
public class fist{
private static boolean ready;
private static int number;
public static class MyThread extends Thread{
@Override
public void run(){
while(!ready);
System.out.println(number);
}
}
public static void main(String args[]) throws InterruptedException {
new MyThread().start();
Thread.sleep(2000);
number = 100;
ready = true;
Thread.sleep(2000);
}
}
上述代码中,MyThread线程只有在数据准备好时(ready为true时),才会打印number的值。他通过ready变量判断是否该打印。在主线程中,开启MyThread线程后,就为number和ready赋值,并期望MyThread线程能看到这些变化并将数据输出。
在虚拟机的client模式下,由于JIT并没有做出足够的优化,在主线程修改ready变量的状态后,MyThread可发现这个改动,并退出程序。但是在server模式下,由于系统优化的结果,MyThread线程无法看到这个改动,导致MyThread线程永远无法退出(while阻塞),这显然不是我们想看到的结果。这个问题就是典型的可见性的问题。
和原子性问题一样,我们只需要简单的使用volatile来申明ready变量,告诉java虚拟机,这个变量可能会在不同的线程中被修改。这样,就可以顺利的解决这个问题了
---------------------