下面七段程序采用的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);
}
}