现代计算机都是冯诺依曼结构的
volatile 变量具备两种特性,其一是保证该变量对所有线程可见,这里的可见性指的是当一个线程修改了变量的值,那么新的值对于其他线程是可以立即获取的。其二 volatile 禁止了指令重排。
多线程的运行可能造成变量数据的不一致
把该变量声明为volatile(不稳定的)即可,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说来,多任务环境下各任务间共享的标志都应该加volatile修饰。
Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。
synchronized开销比volatile大。
volatile不保证原子操作,所以,很容易读到脏数据。
使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。
附录:
Happens-Before法则:
-
程序次序法则:线程中的每个动作A都Happens-Before于该线程中的每一个动作B,在程序中,所有的动作B都出现在动作A之后。
-
Lock法则:对于一个Lock的解锁操作总是Happens-Before于每一个后续对该Lock的加锁操作。
-
volatile变量法则:对于volatile变量的写入操作Happens-Before于后续对同一个变量的读操作。
-
线程启动法则:在一个线程里,对Thread.start()函数的调用会Happens-Before于每一个启动线程中的动作。
-
线程终结法则:线程中的任何动作都Happens-Before于其他线程检测到这个线程已经终结或者从Thread.join()函数调用中成功返回或者Thread.isAlive()函数返回false。
-
中断法则:一个线程调用另一个线程的interrupt总是Happens-Before于被中断的线程发现中断。
-
终结法则:一个对象的构造函数的结束总是Happens-Before于这个对象的finalizer(Java没有直接的类似C的析构函数)的开始。
-
传递性法则:如果A事件Happens-Before于B事件,并且B事件Happens-Before于C事件,那么A事件Happens-Before于C事件。