【发布时间】:2021-01-19 06:56:54
【问题描述】:
好的,我已经在 java 8、11 和 14 上测试了这段代码,它们都有相同的结果。 这是不好的做法和不切实际的情况,但我想了解导致这种情况发生的 JVM 内部。
如果您运行此代码,您会注意到除了 system.out.println 的打印部分本身之外的所有内容如果执行。 在某些时候,使用稍微不同的 java 版本,我设法通过改变“play”太不稳定来打印它,但即使这样现在也不起作用。
请至少在声称它只是使变量死锁或使用缓存之前测试代码,事实并非如此,if 执行并且其中的所有内容都可以正常工作,除了打印部分本身。
public class Main {
public static void main(String[] args) {
TestClass t = new TestClass();
System.out.println("Starting test");
new MyRunnable(t).start();
while (true)
t.testUpdate(System.currentTimeMillis());
}
}
public class MyRunnable extends Thread {
private TestClass t;
public MyRunnable(TestClass t) {
this.t = t;
}
@Override
public void run() {
try {
Thread.sleep(500L);
t.setPlay(true);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TestClass {
private boolean play = false;
private long lastUpdate = 0;
private long updateRate = 2000;
private boolean hasSysoBeenHit = false;
public void testUpdate(long callTime) {
System.out.println(play);
System.out.println((callTime-lastUpdate));
if (this.play && ((callTime-lastUpdate) >= updateRate)) {
System.out.println("Updating! " + (hasSysoBeenHit = true));
this.lastUpdate = callTime;
}
System.out.println("hasbeenhit? " + hasSysoBeenHit);
}
public void setPlay(boolean t) {
System.out.println("Starting game...");
this.play = t;
}
}
【问题讨论】:
-
在互联网上搜索可以很容易地解释这一点。好吧,也许并不容易,但你会很快找到原因。这是因为 JVM 正在收集线程的 println 输出。没有办法解决这个问题,这只是 JVM 的实现方式。如果你想这样做,你需要一种不同的方式来获取数据报告。看看stackoverflow.com/questions/9467759/…
-
什么打印部分不执行?我认为没有问题,除了
play确实需要是volatile -
怎么只有“更新!”在这种情况下被跳过?其他所有内容都以该方法继续打印,所有打印都来自同一个线程,除了一个。它没有过时,也没有明确共享缓冲区,因为其他一切都有效。还有一个事实,为什么它必须是易变的打印(即使不再对我有用了?)是我所追求的。