可见性
可见性:被它修饰的变量对所有线程都可见,当一个线程修改了这个值,新值对于其它线程来说是可以立即得知的。测试代码如下,当flag属性未被volatile修饰时,main方法不会停止,并未在控制台输出“主线程结束”,当使用volatile修饰时,这种情况没有发生,可见volatile具备可见性。
public class Main {
private volatile boolean flag = true;
public void changeFlag() {
flag = false;
}
public static void main(String[] args) {
Main main = new Main();
new Thread(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
main.changeFlag();
System.out.println("值已经改变" + main.flag);
}).start();
while (main.flag) {
}
System.out.println("主线程结束");
}
}
验证禁止指令重排序
运行如下代码,可以看出线程ThreadA中执行a,b,c,d,e,f,g赋值语句不一定按照顺序执行,对它们添加volatile关键字之后,这种情况就不再发生,可见volatile确实能禁止指令重排序。
public class VolatileTest {
public static void main(String[] args) {
VolatileTest main = new VolatileTest();
for (int i = 0; i < 500000; i++) {
main.test();
}
}
public synchronized void test() {
Test test = new Test();
ThreadA t1 = new ThreadA(test);
ThreadB t2 = new ThreadB(test);
t1.start();
t2.start();
}
/**
* 测试volatile时修改为如下代码
* public volatile int a = 0;
* public volatile int b = 0;
* public volatile int c = 0;
* public volatile int d = 0;
* public volatile int e = 0;
* public volatile int f = 0;
* public volatile int g = 0;
* public volatile int h = 0;
*/
static class Test {
public int a = 0;
public int b = 0;
public int c = 0;
public int d = 0;
public int e = 0;
public int f = 0;
public int g = 0;
public int h = 0;
}
static class ThreadA extends Thread {
Test test;
public ThreadA(Test test) {
this.test = test;
}
@Override
public void run() {
test.a = 1;
test.b = 1;
test.c = 1;
test.d = 1;
test.e = 1;
test.f = 1;
test.g = 1;
test.h = 1;
}
}
static class ThreadB extends Thread {
Test test;
public ThreadB(Test test) {
this.test = test;
}
@Override
public void run() {
if (test.b == 1 && test.a == 0) {
System.out.println("b=1");
}
if (test.c == 1 && (test.a == 0 || test.b == 0)) {
System.out.println("c=1");
}
if (test.d == 1 && (test.a == 0 || test.b == 0 || test.c == 0)) {
System.out.println("d=1");
}
if (test.e == 1 && (test.a == 0 || test.b == 0 || test.c == 0 || test.d == 0)) {
System.out.println("e=1");
}
if (test.f == 1 && (test.a == 0 || test.b == 0 || test.c == 0 || test.d == 0 || test.e == 0)) {
System.out.println("f=1");
}
if (test.g == 1 && (test.a == 0 || test.b == 0 || test.c == 0 || test.d == 0 || test.e == 0 || test.f == 0)) {
System.out.println("g=1");
}
if (test.h == 1 && (test.a == 0 || test.b == 0 || test.c == 0 || test.d == 0 || test.e == 0 || test.f == 0 || test.g == 0)) {
System.out.println("h=1");
}
}
}
}