下面七段程序採用的JDK版本爲:1.8.0_201
(1)測試程序1
package com.tj.ythu.thread.jvmvolatile;
import java.util.concurrent.TimeUnit;
/**
* 能正常結束程序
*/
public class Test00 {
private static boolean flag = false;
private static int count = 0;
public static void main(String[] args) {
new Thread(() -> {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("update flag:" + true);
}).start();
while (!flag) {
System.out.println(++count);
// 如果去掉打印語句,直接寫++count,則會進入死循環
// 原因就是println方法假如了synchronized關鍵字
// synchronized:獲得同步鎖、清空工作內存、從主內存中拷貝對象副本到本地內存、執行代碼、刷新主內存數據、釋放同步鎖
}
System.out.println("exit:" + count);
}
}
(2)測試程序2
package com.tj.ythu.thread.jvmvolatile;
import java.util.concurrent.TimeUnit;
/**
* 死循環
*/
public class Test01 {
private static boolean flag = false;
private static int count = 0;
public static void main(String[] args) {
new Thread(() -> {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("update flag:" + true);
}).start();
while (!flag) {
// 這裏會進入死循環,原因是線程(這裏說的是主線程)不會去同步獲取子線程修改後的數據
count++;
}
System.out.println("exit: " + count);
}
}
(3)測試程序3
package com.tj.ythu.thread.jvmvolatile;
import java.util.concurrent.TimeUnit;
/**
* 能正常結束程序
*/
public class Test02 {
private static boolean flag = false;
private static int count = 0;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("update flag:" + true);
});
t1.start();
while (!flag) {
// https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.3
// Thread.sleep和Thread.yield沒有任何同步語義
// 編譯器不必在調用該方法之前將緩存在寄存器中的刷新到共享內存,也不必在調用該方法之後重新加載緩存在寄存器中的值。
// 編譯器可以自由的讀取一次“flag”字段,並在每次循環執行中重用緩存的值。
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
System.out.println("exit: " + count);
}
}
(4)測試程序4
package com.tj.ythu.thread.jvmvolatile;
import java.util.concurrent.TimeUnit;
/**
* 能正常結束程序
*/
public class Test03 {
private static boolean flag = false;
// private static volatile long a1, a2, a3, a4, a5, a6, a7, a8;
// private static volatile long b1, b2, b3, b4, b5, b6, b7, b8;
// private static volatile long c1, c2, c3, c4, c5, c6, c7, c8;
private static volatile int count = 0;
public static void main(String[] args) {
new Thread(() -> {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("update flag:" + true);
}).start();
while (!flag) {
count += 1;
// 爲什麼count加上volatile關鍵字,會影響flag呢?
// 剛開始以爲是Cache Line導致的,發現不是。
}
System.out.println("exit: " + count);
}
}
(5)測試程序5
package com.tj.ythu.thread.jvmvolatile;
import java.util.concurrent.TimeUnit;
/**
* 能正常結束程序
*/
public class Test03_1 {
private static boolean flag = false;
private static Integer count = 0; // 這裏假如換成int類型,則不能退出程序
public static void main(String[] args) {
new Thread(() -> {
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("update flag:" + true);
}).start();
// 爲啥Integer能讓程序獲取到flag的值?
while (!flag) {
count += 1;
}
System.out.println("exit: " + count);
}
}
(6)測試程序6
package com.tj.ythu.thread.jvmvolatile;
/**
* 能正常結束程序
*/
public class Test04 {
private static volatile boolean flag = false;
private static int count = 0;
public static void main(String[] args) {
new Thread(() -> {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("update flag:" + true);
}).start();
// flag 加了volatile屬性,只要發生改變,都會從共享內存中去加載
while (!flag) {
count++;
}
System.out.println("exit: " + count);
}
}
(7)測試程序7
package com.tj.ythu.thread.jvmvolatile;
/**
* 死循環
*/
public class Test05 {
// volatile 加載flag或者count都能正常結束程序
private static boolean flag = false;
private static int count = 0;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
});
Thread t2 = new Thread(() -> {
System.out.println(Thread.currentThread());
while (!flag) {
++count;
}
});
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println(t1.isAlive());
System.out.println(t2.isAlive());
System.out.println("exit:" + count);
}
}