一、第一次读时
二、使用volatile限定的变量被修改时会强制线程使用该变量的主内存中最新的值
三、不确定?
不使用volatile时:
public class TestThread {
private static Boolean flag = false;
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
new Thread(() -> { //线程A
System.out.println("-----cycle start----");
while(!flag) {
}
System.out.println("--------cycle end-----");
}).start();
try {
Thread.sleep(1000*3);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> updateFlag()).start(); //线程B
}
public static void updateFlag() {
System.out.println("-----update flag start---,flag=" + flag);
flag = true;
System.out.println("-----update flag end----,flag=" + flag);
}
}
上面这段代码的运行结果为:
while循环不能结束,线程A中的flag第一次从主内存读取至线程的工作内存时值为false,之后即使线程B修改了flag的值为true后,线程A中while循环依然不能结束,可知线程A使用的flag是线程工作内存中的变量,线程A除了第一次从主内存读取变量flag后再没有重新从主内存读取;
使用volatile,上面代码改为:
public class TestThread {
private static volatile Boolean flag = false;
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
new Thread(() -> { //线程A
System.out.println("-----cycle start----");
while(!flag) {
}
System.out.println("--------cycle end-----");
}).start();
try {
Thread.sleep(1000*3);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> updateFlag()).start(); //线程B
}
public static void updateFlag() {
System.out.println("-----update flag start---,flag=" + flag);
flag = true;
System.out.println("-----update flag end----,flag=" + flag);
}
}
运行结果为:
使用volatile后while循环顺利结束,线程A中的flag第一次从主内存读取至线程的工作内存时值为false,之后即使线程B修改了flag的值为true后,线程A中while循环顺利结束,可知线程A使用的flag是在线程B修改变量flag并写入主内存后从主内存重新读取的;
再一次修改上面的代码,不使用volatile:
public class TestThread {
private static Boolean flag = false;
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
new Thread(() -> { //线程A
System.out.println("-----cycle start----");
while(!flag) {
// 可以结束while循环
//System.out.println("ok");
//new HashMap<>();
//synchronized(TestThread.class) {}
/*try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
// 不可以结束while循环
new Integer(10);
new ArrayList<>();
boolean is = flag;
}
System.out.println("--------cycle end-----");
}).start();
try {
Thread.sleep(1000*3);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> updateFlag()).start(); //线程B
}
public static void updateFlag() {
System.out.println("-----update flag start---,flag=" + flag);
flag = true;
System.out.println("-----update flag end----,flag=" + flag);
}
}
但是运行结果为:
while循环顺利结束,线程A在线程B修改了flag的值后,重新从主内存中读取了flag;
总结:
线程在什么情况下会从主内存读取数据?
第一次读时,使用volatile限定的变量被修改时会强制线程使用该变量的主内存中最新的值,线程经过了阻塞状态,线程中有IO,获取锁/释放锁...