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

标签 java multithreading

类(class)大纲:
我们有两个线程(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 hibernate 多长时间),它都会快速连续打印 102 或 409。然后,打印停止(永远)。

这里到底发生了什么?

最佳答案

container.a 不是 volatile 并不意味着它被 t3 强制缓存。这意味着无法保证是否会。

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

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

至于为什么在您测试的确切环境中会出现这种确切行为,我们只能猜测。但我的钱是在理论上,当代码按解释运行时,它每次都会去读取 container.a,但是一旦它被 Hotspot 编译为 native 代码,该值只会被加载进入寄存器一次,这就是它的结束。您可以使用 -XX:+PrintCompilation 命令行标志来验证这个假设。

关于java - 多线程 - 为什么下面的程序表现得如此奇怪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52389874/

相关文章:

java - Cassandra 跟踪和客户端延迟之间的差异

c# - 调用计时器线程返回时线程不会停止

java - 偶尔出现并发修改异常

java - 如何强制两个 Java 线程在同一个处理器/核心上运行?

c# - 为什么 Windows 窗体应用程序 (C#) 会死锁以及如何避免死锁?

android - 优先考虑新 Activity

java - 京都内阁/伯克利 DB : Hash table size limitations

java - ListViewDragginanimation 中的自定义 ListView 项

java - JSON Jackson ObjectMapper ReadValue - 转换日期时出错

java - 删除 Miglayout 中父容器边框的间隙