代码之家  ›  专栏  ›  技术社区  ›  Sudix

多线程-为什么下面的程序会表现得如此奇怪?

  •  8
  • Sudix  · 技术社区  · 6 年前

    课程大纲:
    我们有两条线( t1 t2 )写入一个整数值,然后将写入的值刷新到RAM。
    另一条线( t3 )检查值是否与 T1 T2 如果没有,打印出来。

    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 将缓存 不要打印任何东西。

    实际发生的情况:
    一秒钟左右(不管你让多久 T3 睡眠),它可以快速连续打印102或409。然后,打印停止(永久)。

    这里到底发生了什么?

    1 回复  |  直到 6 年前
        1
  •  11
  •   biziclop    6 年前

    container.a 不易波动并不意味着它被强制缓存 t3 . 它的全部意思是,没有保证它是否会是。

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

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

    至于为什么要在你测试过的环境中进行这种精确的行为,我们只能猜测。但我的钱是基于这样一种理论:当代码按解释运行时,它将继续运行并读取 容器。 每次,但一旦它被热点编译成本机代码,该值只被加载到一个寄存器中一次,这就是它的结尾。您可以使用 -XX:+PrintCompilation 命令行标志。