多线程-以下程序为何如此奇怪?

时间:2018-09-18 15:20:56

标签: java multithreading

程序概述:
 我们有两个线程(t1t2)写入一个整数值,然后将写入的值刷新到RAM。
另一个线程(t3)检查该值是否与t1t2所写的值相符,如果不一致,则打印该值。

public class Container
{
     int a;
     volatile boolean b;


    public static void main(String[] args)
    {
        Container container = new Container();

        Thread t1 = new Thread()
        {
            @Override
            public void run()
            {
                for (;;)
                {
                    container.a = 409;
                    container.b ^= container.b;

                }
            }
        };

        Thread t2 = new Thread()
        {
            @Override
            public void run()
            {
                for (;;)
                {
                    container.a = 102;
                    container.b ^= container.b;
                }
            }
        };

        Thread t3 = new Thread()
        {
            @Override
            public void run()
            {
                try
                {
                    Thread.sleep(100);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
                for (;;)
                {
                    if (container.a != 409 && container.a != 102 )
                        System.out.println(container.a);
                }
            }
        };

        t1.start();
        t2.start();
        t3.start();
    }
}

我认为会发生的事情:
由于a不是volatile,因此我认为t3会缓存a而从不打印任何内容。

实际发生的情况:
一秒钟左右(无论您使t3处于休眠状态),它都会快速连续打印102或409。然后,打印停止(永远)。

这里到底发生了什么?

1 个答案:

答案 0 :(得分:11)

container.a不易失并不意味着它被t3强制缓存。这意味着没有任何保证。

可以自由打印任何值的原因是这里的使用时间检查问题:

if (container.a != 409 && container.a != 102 )
   System.out.println(container.a);

至于为什么在您测试它的确切环境中出现这种确切行为,我们只能猜测。但是我的钱是基于这样的理论,即代码以解释的方式运行时,每次都会去读取container.a,但是一旦Hotspot将其编译为本地代码,则该值只会被加载到寄存器一次,到此为止。您可以使用-XX:+PrintCompilation命令行标志来验证这一假设。