1.锁的释放与获取所建立的happens-before关系:
public class Demo {
private int value;
public synchronized void a() {
value++; //1
}
public synchronized void b() {
int a = value; //2
}
}
根据volatile变量规则,1happens-before2。
锁的获取和释放的内存语义:锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。
2.volatile的内存语义
volatile读写所建立的happens-before关系:
public class Demo {
private volatile int a;
private volatile boolean flag;
public void writer() {
a = 1; //1
flag = true; //2
}
public void reader() {
if (flag) { //3
int b = a + 1; //4
System.out.println(a); //5
}
}
}
根据程序顺序性规则,1happens-before2,3happens-before4,4happnes-before5。根据volatile变量规则,2happens-before3。根据传递性规则,1happens-before4。
volatile读写的内存语义:当一个线程对volatile的变量进行写操作时Java的内存模型会将该线程对应的本地内存的共享变量刷新到主内存中去。当一个线程读一个volatile变量时,Java内存模型会把当前线程对应的本地内存中的共享变量置为无效,然后从主内存中重新读取该共享变量。
3.final的内存语义
写final域的重排序规则: 写final域的重排序规则禁止把final域的写重排序到构造方法之外。Java的内存模型禁止编译器把final域的写重排序到构造方法之外。编译器会在final域的写之后,在构造方法执行完毕之前,插入一个内存屏障StoreStore,保证处理器把final域的写操作在构造方法中执行。处理器通过内存屏障来禁止把final域的写重排序到构造方法之外。LoadLoad、StoreStore、LoadStore、StoreLoad屏障。
public class Demo {
private int a;
private final int b;
public Demo {
b = 10;
}
}
读final域的重排序规则:在一个线程中,初次读对象引用和初次读该对象所包含的final域,Java内存模型禁止处理器重排序这两个操作。
final域为静态类型:final域的初始化只在类加载时执行一次,类加载保证线程安全。
fianl域为抽象类型:在构造方法内对一个final引用的对象的成员域的写入,与随后在构造方法外把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
public class Demo {
private final Object obj;
public Demo() {
obj = new Object(); // 1
}
private Demo demo;
private void w() {
demo = new Demo();
}
public void r() {
Demo d = demo; //2
}
}
1和2不能重排序。