转载:http://blog.csdn.net/feier7501/article/details/20001083java
在当前的Java内存模型下,线程能够把变量保存在本地内存(好比机器的寄存器)中,而不是直接在主存中进行读写。这就可能形成一个线程在主存中修改了一个变量的值,而另一个线程还继续使用它在寄存器中的变量值的拷贝,形成数据的不一致。 ide
要解决这个问题,只须要像在本程序中的这样,把该变量声明为volatile(不稳定的)便可,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。通常说来,多任务环境下各任务间共享的标志都应该加volatile修饰。
spa
Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。并且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任什么时候刻,两个不一样的线程老是看到某个成员变量的同一个值。 .net
用volatile和不用volatile的区别,运行一下,就知道了。线程
不用volatile:code
- package com.keyword;
-
- public class TestWithoutVolatile {
- private static boolean bChanged;
-
- public static void main(String[] args) throws InterruptedException {
- new Thread() {
-
- @Override
- public void run() {
- for (;;) {
- if (bChanged == !bChanged) {
- System.out.println("!=");
- System.exit(0);
- }
- }
- }
- }.start();
- Thread.sleep(1);
- new Thread() {
-
- @Override
- public void run() {
- for (;;) {
- bChanged = !bChanged;
- }
- }
- }.start();
- }
-
- }
运行后,程序进入死循环了,一直在运行。blog
用volatile:ip
- package com.keyword;
-
- public class TestWithVolatile {
- private static volatile boolean bChanged;
-
- public static void main(String[] args) throws InterruptedException {
- new Thread() {
-
- @Override
- public void run() {
- for (;;) {
- if (bChanged == !bChanged) {
- System.out.println("!=");
- System.exit(0);
- }
- }
- }
- }.start();
- Thread.sleep(1);
- new Thread() {
-
- @Override
- public void run() {
- for (;;) {
- bChanged = !bChanged;
- }
- }
- }.start();
- }
-
- }
程序输出!=,而后立刻退出。内存
可是,不少状况下,用不用volatile,感受不出什么区别,何时要用volatile呢?看看JDK里使用volatile的类。get
好比java.util.regex.Pattern里的变量:
- private transient volatile boolean compiled = false;
还有,java.lang.System的变量:
- private static volatile Console cons = null;
通常就是初始化的时候,须要用到volatile。
java.util.Scanner里的变量,如:
- private static volatile Pattern boolPattern;
- private static volatile Pattern separatorPattern;
- private static volatile Pattern linePattern;
初始化boolPattern的代码:
- private static Pattern boolPattern() {
- Pattern bp = boolPattern;
- if (bp == null)
- boolPattern = bp = Pattern.compile(BOOLEAN_PATTERN,
- Pattern.CASE_INSENSITIVE);
- return bp;
- }
上面的状况,可使用synchronized来对boolPattern加锁,可是synchronized开销比volatile大,volatile可以胜任上面的工做。
volatile不保证原子操做,因此,很容易读到脏数据。
使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,没必要使用。