package pc.demo.JAVADEMO.DXC;
import java.util.concurrent.TimeUnit;
class ShareData {
// TODO 使用 valatile 关键字修饰, 禁止重排序,和保证可见性,不保证原子性,原理内存屏障
// volatile int number = 0;
int number = 0;
public void setNumberTo100() {
this.number = 100;
}
}
public class Demo {
public static void main(String[] args) {
// 资源类
ShareData shareData = new ShareData();
// 子线程 实现了Runnable接口的,lambda表达式
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t come in");
// 修改number的值
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 修改 值后 会在某一个时刻 写会 主内存
shareData.setNumberTo100();
// 输出修改后的值
System.out.println(Thread.currentThread().getName() + "\t update number value:" + shareData.number);
}, "子线程").start();
new Thread(() -> {
while(shareData.number==0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "\t update number value:" + shareData.number);
}, "子线程2").start();
// main线程就一直在这里等待循环,直到number的值不等于零
while(shareData.number == 0) {
// TODO 此处输出 加了 synchronized 锁,Synchronized可以保证共享变量的可见性
System.out.println(shareData.number);
// TODO 此处使用休眠, 线程发生上下文切换,被别的线程抢占了时间片,重新获取时间片便会加载主内存的值
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// TODO JMM 内存模型 线程变量副本失效,重新从 主内存中读取,有不确定性
// 业务耗时
// ....
}
// 按道理这个值是不可能打印出来的,因为主线程运行的时候,number的值为0,所以一直在循环
// 如果能输出这句话,说明子线程在睡眠3秒后,更新的number的值,重新写入到主内存,并被main线程感知到了
System.out.println(Thread.currentThread().getName() + "\t 主线程感知到了 number 不等于 0");
/**
* 最后输出结果:
* 子线程 come in
* 子线程 update number value:100
* 最后线程没有停止,并行没有输出"主线程知道了 number 不等于0"这句话,说明没有用volatile修饰的变量,变量的更新是不可见的
*/
}
}