public class Volatile {
public static void main(String[] args) {
final Volatile volObj = new Volatile();
Thread t2 = new Thread() {
public void run() {
while (true) {
volObj.check();
}
}
};
t2.start();
Thread t1 = new Thread() {
public void run() {
System.out.println(volObj.boolValue);
while (true) {
volObj.swap();
}
}
};
t1.start();
}
boolean boolValue;// use volatile to print "WTF!"
public void check() {
if (boolValue == !boolValue)
System.out.println("WTF!");
}
public void swap() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolValue = !boolValue;
}
}
以上代码出自网络。
如上代码如果把boolValue用volatile修饰的话,就会打印出WTF。([color=red]volatile可以保证任何一个线程在读取该域的时候可以读取到最近被写入的值-- effective java [/color])。
1.原因是 if (boolValue == !boolValue) 并不是一个原子操作,读第二个boolValue的时候这时可能已经被另外一个线程中的swap()方法修改了值。所以打印出"WTF"
2.当没有加volatile修饰boolValue的时候,每个线程的boolValue都是主内存中boolValue的一个拷贝,gvm并不保证何时线程中的boolValue会同步主内存中。在这个例子中,我们可以这样理解,每个线程维护者主内存的boolValue的一个拷贝,它们之间并不影响。所以几乎不会发生打印出"WTF"的情况。
3.如果在代码块中增加synchronized块的话,即使使用volatile修饰boolValue也不会打印出"WTF" ,synchronized(this){}修饰这两段代码,避免了两个线程之间的“交叉”从而不会出现1的情况。
synchronized(this){
if (boolValue == !boolValue)
System.out.println("WTF!");
}
synchronized(this){
boolValue = !boolValue;
}
volatile修饰符不执行互斥访问,但是它可以保证任何一个线程在读取该域的时候可以读取到最近被写入的值。---effective java