volatile int x=1;//告诉编译器对这个x变量的读写不能使用CPU缓存,必须从内存中读或者写,但是实际运用中的困惑却很多!
public class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42;
v = true;
}
public void reader() {
if (v) {
System.out.println("x = " + x);
}
}
}
class Test {
public static void main(String[] args) throws InterruptedException {
VolatileExample volatileExample = new VolatileExample();
Thread A = new Thread(volatileExample::writer);
Thread B = new Thread(volatileExample::reader);
A.start();
B.start();
A.join();
B.join();
}
}
//x = 42
解释:线程A执行writer方法,安装volatile语义会把变量“v=true”写到内存中,此时线程B执行reader方法,线程B会从内存中读取变量V,此时x结果为42。(java版本必须保证在1.5之后)
JAVA1.5解决了CPU缓存导致可见性问题,Happens-Before规则。
Happens-Before:前面一个操作的结果对后续的操作是可见的。
约束了编译器的优化的行为,编译器优化必须遵循Happens-Before原则(6个原则)。
1.程序代码片段的顺序性规则
// 以下代码来源于【参考 1】
1class VolatileExample {
2 int x = 0;
3 volatile boolean v = false;
4 public void writer() {
5 x = 42; //对x进行赋值 写
6 v = true;//对v进行赋值 写
7 }
8 public void reader() {
9 if (v == true) {//此时需要读v
10 // 这里 x 会是多少呢?
11 }
}
}
代码第5行x=42,对于第6行v=true来讲是可见的。(规则1)称之5 happens-before于6
一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。
final:
修饰变量的时候,告诉编译器,这个变量生而不变(内地地址)。
在正确的构造函数中没有“逸出”就不会出现问题!
// 以下代码来源于【参考 1】
final int x;
// 错误的构造函数
public FinalFieldExample() {
x = 3;
y = 4;
// 此处就是讲 this 逸出,
global.obj = this;
}