类(class)大纲:
我们有两个线程(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
会缓存 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/