线程安全问题(内存可见性)
导致的原因
内存可见性问题的出现主要是因为编译器优化多线程导致的
示例代码
package 线程安全问题;import java.util.Scanner;/*** Created with IntelliJ IDEA.* Description:* User: wuyulin* Date: 2023-07-26* Time: 13:49*/
public class Demo2 {private volatile static int isQuit=0;public static void main(String[] args) {Thread A=new Thread(()->{while (isQuit==0){}});Thread B=new Thread(()->{Scanner sc=new Scanner(System.in);System.out.print("isQuit=");isQuit=sc.nextInt();});A.start();B.start();}
}
出现的问题
在上述代码中如果isQuit成员变量不加上volatile关键字的话,该程序就会出现bug,即使在B线程中修改了isQuit的值,在A线程中依然不会退出循环
出现问题的原因
出现该问题的原因是编译器对我们的代码进行了优化
因为isQuit==0分为两步操作,1.将isQuit从内存中读取到寄存器中,2.在寄存器中进行isQuit与0的比较
而从内存中读取数据到寄存器中要消耗很长的时间,在寄存器中进行isQuit与0的比较消耗的时间很短
编译器发现经过了很多次的循环isQuit的值都没有改变,于是做了一个大胆的决定,将从内存中读取isQuit这个操作优化掉,采用读取寄存器中的值,效率便得到了极大的提高
但是此时在B线程中修改isQuit在内存中的值,A线程由于已经不在内存中读取isQuit的值了,所以A线程的循环不会受到影响,就导致了无法停止A线程的循环
解决的方法
解决的方法:在isQuit成员变量声明时加上volatile(易变的)关键字,表示该成员变量是易变的,此时编译器就不会优化掉去内存中读取isQuit值的操作,这样B线程改变了内存中isQuit的值,A线程便能够读取到,结束循环