多线程之可见性问题案例

多线程之可见性问题案例

有如下代码:

public class MyThread05 {
    private static boolean f = true;

    public static void main(String[] args) throws InterruptedException {
        //新建线程,不断访问共享变量的值
        new  Thread(()->{
            /**
             * Java虚拟机中的即时编译器会对一些热点代码像循环这些,进行优化
             * 这里while循环中的读取f到的值总是为true
             * 它就会优化代码,将while循环里面的条件判断改为true
             * while(f) ----> while(true)
             */
            while(f) {
			
            }
        }).start();  //线程二改变共享变量的值为false后,依旧进行死循环不停止

        Thread.sleep(1000);

        //新建线程,改变共享变量的值
       Thread t2 =new Thread(()->{
            f = false;
            System.out.println("第二个线程改变了共享变量的值" + f);
        });

        t2.start();
        t2.join(); //保证t2线程结束后

        System.out.println(Thread.currentThread().getName() + "获取到共享变量的值" + f);
    }
}

执行该程序时,线程1获取到共享变量f为true,并作为while循环的判断条件,形成死循环。
当线程2抢占到执行权时,修改了共享变量f为false,为了判断线程1是否真的修改了f的值为false,我们新加一个main线程获取f实际的值。在此之前我们先用Thread.join()方法,让线程2修改f值结束后,在获取f的值。
为了保证线程1优先抢占到执行权,获取f值为true,我们使用sleep()方法。
执行程序,得到如下结果:
多线程之可见性问题案例_第1张图片
可以看到,共享数据f的值确实被线程2修改为false,main线程获取到的值也为false。但是程序却没有终止,也就是说while循环还在继续。

问题

那么就有问题了,我的线程2已经在有执行权的时候修改f的为false,那么随之我线程1里获取到f的值也应该为false啊,while循环应该退出,程序停止。那么为什么或有这种现象呢?

什么是热点代码(转载)

对于程序来说,通常只有一部分代码会被经常执行,而应用的性能主要取决于这些代码执行得有多快。这些关键代码段被称为应用的热点代码,代码执行得越多就被认为是越热。

因此JVM执行代码时,并不会无脑编译代码。第一,如果代码只执行一次,那编译完全就是浪费精力。对于只执行一次的代码,解释执行Java字节码比先编译然后执行的速度快。但如果代码是经常被调用的方法,编译就值得了:编译的代码更快,多次执行累积节约的时间远超过了编译所花费的时间。

这种权衡是编译器先解释执行代码的原因之一:编译器可以找出哪个方法被调用得足够频繁,可以进行编译。第二个理由是为了优化: JVM执行特定方法或者循环的次数越多,它就会越了解这段代码。这使得JVM可以在编译代码时进行大量优化。

https://blog.csdn.net/weixin_29256771/article/details/114834936

解释

这是jvm中的优化机制,在我们的程序运行时,会有一些热点代码是会被我们高频率的应用的,像循环这种。因为我们线程1中写的是相当于while(true)的一个死循环,会被执行若干次,所以这个时候会被我们的jvm标记为热点代码,虚拟机就会对我们的代码进行一个优化。比如我的条件判断f=true,它就会优化我的代码为while(f) ----> while(true),那么这个时候我线程1中的while循环就不会在受共享变量f的值左右了。条件判断恒等于true。
这就是多线程中的可见性问题

可见性问题

在这两个线程中,他们是并行的,当线程1修改了共享变量,那么我的线程2不能及时的知道f变量值被修改了,所以我们的程序不会停止运行。

解决

在我们的共享变量前用volatile关键字修饰,告诉我们的Java虚拟机这是要用的,不要优化它,它就不会被更改。

private volatile static boolean f = true;

再次执行程序:
多线程之可见性问题案例_第2张图片
发现程序运行结束。线程1知道我们的共享变量值修改为false。

你可能感兴趣的:(java学习,jvm,java,开发语言)