volatile的分析
可见性
可见性指的是线程之间的可见性,一个线程修改的状态对于另一个线程是不可见的。
volatile的定义
在Java中使用volatile来保证可见性。volatile修饰的变量不运行线程内部缓存和重排序,即直接修改内存。
这里有一个指的注意的问题,volatile修饰的变量不能保证原子性,只能保证可见性。
一个不可见的例子:
class VisibilityThread extends Thread {
private boolean stop = false;
public void run() {
int i = 0;
System.out.println("start loop.");
while(!getStop()) {
i++;
}
System.out.println("finish loop,i=" + i);
}
public void stopIt() {
stop = true;
}
public boolean getStop(){
return stop;
}
}
public class NoVisibility2 {
public static void main(String[] args) throws Exception {
VisibilityThread v = new VisibilityThread();
v.start();
//停顿1秒等待新启线程执行
Thread.sleep(1000);
System.out.println("即将置stop值为true");
v.stopIt();
Thread.sleep(1000);
System.out.println("finish main");
System.out.println("main中通过getStop获取的stop值:" + v.getStop());
}
}
如果一个字段被声明为volatile,Java线程模型确保了所有线程看到的变量是一致的。
为了提供处理器速度,处理器不直接和内存进行通信,而是先将系统内存中的数据读到内部缓存(可能是多级缓存)后在进行操作,但操作玩不知道何时写会到内存。如果变量对于volatile变量进行写操作,JVM就会向处理器发出一条Lock前缀的指令,将这个变量的缓存行写回到内存中。
Lock指令在多核处理器下会发生的两件事:
- 将当前处理器缓存行的数据写回到系统内存。
- 这个写回内存的
但是就算写会到内存,如果其它处理器缓存的值还是旧值,再执行计算操作就会有问题。所以,在多处理器下,为了保证各个处理器的缓存一致的,就会实现缓存一致性,每一个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存设置为无效,当多个处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理机缓存中。
image
网友评论