完整代码: https://github.com/Sheldor5/JavaGPP(请参阅两个选项的测试)
我对命令模式和循环有一些奇怪的行为(倒数直到应该执行实际的命令操作):
我想要实现的目标:
我目前正在开发一款游戏,在这个游戏中我想放置一个"炸弹"这个"炸弹"应爆炸,例如爆炸2秒。我使用命令模式执行此操作,其中一种类型的命令从左delta
变量中减去timeLeft
,直到timeLeft
变量为< = 0 - >所以如果2秒钟过去就应该发生爆炸。如果我在while循环中执行命令,这是行不通的,因为炸弹在+2.2秒之后而不是在2之后(和一些nanos)爆炸。如果我在循环中添加Thread.sleep(1)
,那么时间对我来说足够准确,所以我可以说delta
的计算已经完成了。
选项1:
// infinite loop: execute all commmands in the executor (only one command for now)
while (true) {
commandExecutor.executeCommands();
}
// the only one command in the executor gets called everytime
public static final long NANOS = 1000000000;
private long timeLeft = NANOS;
private long start;
public Command() {
this.start = System.nanoTime();
}
public execute(final long delta) {
this.timeLeft -= delta;
if (this.timeLeft <= 0) {
final long time = System.nanoTime() - this.start;
System.out.println(String.format("Successfully executed Command with ID '%s' in %dns (%dns)", this.getID(), time, this.timeLeft));
this.timeLeft += NANOS;
}
}
预期输出(1秒间隔):
使用ID&#39; 1&#39;成功执行了命令在1000000454ns(-454ns)
使用ID&#39; 1&#39;成功执行了命令在1000000695ns(-695ns)
使用ID&#39; 1&#39;成功执行了命令在1000000549ns(-549ns)
使用ID&#39; 1&#39;成功执行了命令在1000000003ns(-3ns)
实际输出():
使用ID&#39; 1&#39;成功执行了命令在1267062727ns(-266ns)
使用ID&#39; 1&#39;成功执行了命令在1350811695ns(-165ns)
使用ID&#39; 1&#39;成功执行了命令在1352353549ns(-145ns)
使用ID&#39; 1&#39;成功执行了命令在1263098003ns(-75ns)
但是如果我在循环中添加Thread.sleep()
,实际输出会更精确:
选项2:
while (true) {
commandExecutor.executeCommands();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
可接受的输出:
使用ID&#39; 40&#39;成功执行Command4在1000015964ns(-47338ns)
使用ID&#39; 40&#39;成功执行Command4在1001095472ns(-316309ns)
使用ID&#39; 40&#39;成功执行Command4在1000039457ns(-224116ns)
使用ID&#39; 40&#39;成功执行Command4在1001043666ns(-662982ns)
有人可以向我解释一下吗?循环太快了吗?事情是如此之快以至于它无法识别变量的实际价值而错误地将其视为大于零?为什么会有这么大的差异,那些〜0.2秒?
答案 0 :(得分:0)
最初我认为这是一个并发问题,但我不认为这是因为您的自定义执行程序和命令不会产生任何新线程。相反,我认为你只是过多地投入时间。您的代码基本上只是循环并调用System.nanotime()
。使用delta
变量的方法存在的问题是,您没有考虑调用System.nantime ()
所涉及的时间。但是你要打电话了很多。我认为使用计时器任务会更好,但如果你想自己尝试这样做,请尝试以下内容:
long start = System.nanotime ();
long inTwoSecs = start + 2000000000L;
while (true) {
long now = System.nanotime ();
if (now >= inTwoSecs) {
return;
}
}