美团外卖网站开发,鸿顺里网站建设,怎么更改网站名称,域名转接的流程内存可见性 一:内存可见性1.2: 二:解决内存可见性问题2.1 volatile关键字2.2:synchronized关键字解决内存可见性问题 一:内存可见性
public class Demo1 {public static int count 0;public static void main(String[] args) throws InterruptedException {Thread t1new Thre… 内存可见性 一:内存可见性1.2: 二:解决内存可见性问题2.1 volatile关键字2.2:synchronized关键字解决内存可见性问题 一:内存可见性
public class Demo1 {public static int count 0;public static void main(String[] args) throws InterruptedException {Thread t1new Thread(()-{while(count0){}System.out.println(t1线程结束);});Thread t2new Thread(()-{Scanner scannernew Scanner(System.in);1System.out.println(请输入一个整数:);countscanner.nextInt();});t1.start();t2.start();}
}
上述代码预期效果: t1线程首先进入循环,当用户输入一个非0整数的时候,就会使t1线程退出循环.结束线程. 但t1实际上并没有真正出现退出的情况,这也是bug,而产生上述现象的原因,就是**“内存可见性”** while(count0){}从指令角度分析这段代码: (1)load :从内存读取数据到CPU 寄存器中, (2)cmp:比较,条件成立,继续循环,条件不成立,退出循环. 然而,一个load指令消耗的时间,会比一个cmp指令消耗的时间多得多,执行一次load的时间,等于上万次cmp执行消耗的时间. 同时,JVM发现每次load执行的结果,是一样的(t2线程修改之前),因此,**JVM就把上述load操作优化掉了,只是第一次真正进行load,后续再执行到load,而是直接读取已经load过的寄存器中的值了(读取寄存器的速度远远大于 读取内存的速度).**当t2线程修改count的值,但由于t1线程并没有从内存中重新读取,所以获取不到更新后的值.
1.2:
public class Demo1 {public static int count 0;public static void main(String[] args) throws InterruptedException {Thread t1new Thread(()-{while(count0){System.out.println(hello );}System.out.println(t1线程结束);});Thread t2new Thread(()-{Scanner scannernew Scanner(System.in);System.out.println(请输入一个整数:);countscanner.nextInt();});t1.start();t2.start();}
}
当我们在 while(count0){System.out.println(hello );}while循环中打印,就会发现代码又和我们预期的效果一样了,这又是为什么??? 因为循环体内存在IO操作,而IO操作是从硬盘中获取数据,因此IO操作消耗的时间比load操作消耗的时间更多,并且IO操作是不能被优化掉的. 总结:上述问题本质上是编译器优化引起的(优化是由javac和java配合完成的工作),优化掉load操作之后,使t2线程的修改,没有被t1线程感知到,这就造成了内存可见性问题
二:解决内存可见性问题
2.1 volatile关键字
编译器什么时候优化,什么时候不优化,这是一个玄学问题. 通过volatile关键字,解决优化问题,让编译器不再优化. 当给变量修饰上volatile关键字之后,编译器就知道了,这个变量是反复无常的,编译器就不会再进行优化了 volatile 是专门针对内存可见性的场景来解决问题的,告诉编译器不要进行优化操作.
public class Demo1 {public volatile static int count 0;public static void main(String[] args) throws InterruptedException {Thread t1new Thread(()-{while(count0){}System.out.println(t1线程结束);});Thread t2new Thread(()-{Scanner scannernew Scanner(System.in);System.out.println(请输入一个整数:);countscanner.nextInt();});t1.start();t2.start();}
}
2.2:synchronized关键字解决内存可见性问题
synchronized关键字,和volatile关键字处理逻辑上是不同的. 引入synchronized关键字,是因为加锁操作本身太重量了,相比load 来说,开销更大,编译器自然就不会对load 优化了(和sleep ,IO操作原理类似).
public class Demo1 {public static int count 0;public static void main(String[] args) throws InterruptedException {Object locker new Object();Thread t1new Thread(()-{while(count0){synchronized (locker){{}}}System.out.println(t1线程结束);});Thread t2new Thread(()-{Scanner scannernew Scanner(System.in);System.out.println(请输入一个整数:);countscanner.nextInt();});t1.start();t2.start();}
}