并发编程中,多线程共享变量之间的可见性,可以总结为六项 Happens-Before 规则(可见性规则)。
Happens-Before 规则:前面一个操作的结果对后续操作是可见的。
六项规则:
1. 顺序性规则
前面的操作 Happens-Before 于后续的任意操作,也就是前面做的操作,后面是可见的。
2. volatile 变量规则
对一个 volatile 修饰的变量的修改操作, Happens-Before 于后续对这个 volatile 变量的读操作。
例如A线程对volatile x的值修改为2,B线程get x,能够感知到x的值变为了2。
3. 传递性
如果 A Happens-Before B,且 B Happens-Before C,那么 A Happens-Before C。
4. 同步锁的规则
对一个锁的解锁 Happens-Before 于后续对这个锁的加锁。
即相同的锁,相同的代码块,前面加锁做的操作,对后加锁都是可见的。
5. 线程 start() 规则
线程A中调用了线程B的start()方法,那么线程A调用线程B的start()方法之前的操作,对线程B都是可见的。
也就是该 start() 操作 Happens-Before 于线程 B 中的任意操作。
6. 线程 join() 规则
线程 A 调用子线程 B 的 join() 方法,当线程 B 完成后返回,线程A能够看到线程B中的操作。当然所谓的“看到”,指的是对共享变量的操作。
我们来看几个原则的示例。
规则2:
public class VolatileTest {
int x = 0;
volatile boolean status = false;
public void write(String threadName) {
System.out.println("线程进入write方法:"+threadName);
x = 10;
status = true;
}
public void read(String threadName) {
System.out.println("线程进入read方法:"+threadName);
if(status) {
System.out.println(threadName +":"+ x);
}
}
public static void main(String[] args) {
VolatileTest vt = new VolatileTest();
new Thread(()->vt.write(Thread.currentThread().getName())).start();
new Thread(()->vt.read(Thread.currentThread().getName())).start();
}
}
输出:
线程进入write方法:Thread-0
线程进入read方法:Thread-1
Thread-1:10
规则5:
public class ThreadStartTest {
private int x = 0;
public static void main(String[] args) throws InterruptedException {
ThreadStartTest tst = new ThreadStartTest();
Thread thread = new Thread(() -> {System.out.println(tst.getX());tst.setX(10);});
thread.start();
tst.setX(5);
Thread.sleep(1000);
System.out.println(tst.getX());
}
public void setX(int value) {
x = value;
}
public int getX() {
return x;
}
}
输出:
5
10
规则6:
public class ThreadJoinTest {
private static int x = 0;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> x = 5);
thread.start();
thread.join();
System.out.println(x);
}
}
输出:
5