/**
* volatile 保证线程的可见性 禁止指令重排
* 线程可见性:在计算机中每个程序都是运行在自己的本地工作内容中的,同时计算机本身也有自己的主内存,
* 每个程序需要将主内存中的信息拷贝一份数据到本地内存之中,使用完毕之后再写回给主内存。
* 因此在线程同步支持的过程中 线程与线程之间的数据是不可见的。 volatile保证了线程之间的可见性。 扩展--MSEI 缓存一致性原理
*
* 指令重排:在正常的程序中程序一般都会去顺序从上往下执行,但是编译器有时候不会按照我们代码写的顺序执行。
* 因此在执行过程中会出现顺序的问题。 使用例子:单例模式
* 得益于JAVA的 先行发生原则(happen-before原则) 防止指令重拍
*/
public class VolatileJichu {
volatile boolean flag = true;
void m (){
System.out.println("start..");
while(flag) {
}
System.out.println("end...");
}
public static void main(String[] args) throws InterruptedException {
VolatileJichu volatileJichu = new VolatileJichu();
new Thread(volatileJichu::m, "t").start();
Thread.sleep(100);
volatileJichu.flag = false;
}
}
/**
* 在非常非常高并发的场景下, 在实例化一个对象可以分为三步,第一步分配内存空间,第二步实例初始化对象,第三步赋值给栈的内存引用
* 因此当一个线程在初始化对象的时候会发生指令重排,有可能赋值还没有完成,这时候第二个线程获取对象,对象此时所指的是个空对象。导致数据不同。。
*/
public class Singleton {
private static Singleton singleton;
//私有构造方法
private Singleton(){}
public static Singleton getSingleton(){
if (singleton == null){
synchronized (Singleton.class) {
if (singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(getSingleton().hashCode());
}).start();
}
}
}