添加一个没有 Thread.sleep 的延迟和一个啥都不做的 while 循环

Posted

技术标签:

【中文标题】添加一个没有 Thread.sleep 的延迟和一个啥都不做的 while 循环【英文标题】:Adding a delay without Thread.sleep and a while loop doing nothing添加一个没有 Thread.sleep 的延迟和一个什么都不做的 while 循环 【发布时间】:2014-01-24 10:30:13 【问题描述】:

我需要在不使用 Thread.sleep() 或什么都不做的 while 循环的情况下添加延迟。 游戏即时编辑(我的世界)时钟在“滴答”上运行,但它们可能会根据您的 FPS 波动。

public void onTick() //Called every "Tick"
    if(variable) //If my variable is true
            boolean = true; //Setting my boolean to true
            /**
            *Doing a bunch of things.
            **/
            //I need a delay for about one second here.
            boolean = false; //Setting my boolean to false;
    

我需要延迟的原因是,如果我没有延迟,代码会运行得太快而错过它并且不会切换。

【问题讨论】:

为什么不能使用Thread.sleep() 添加任意延迟,因为代码“运行太快”是主要代码气味。在大多数情况下,一次保持整个线程一秒钟也是完全不可接受的。更多详细信息将有助于您在此处找到更好的解决方案。 我不能使用 Thread.sleep() 因为它会在你设置的时间内冻结整个游戏。 那么,你认为我们可以提供一些任意循环吗? Thread.sleep 不会像循环那样消耗 CPU 周期……听起来你有设计问题。你需要一个单独的线程来处理游戏模型的更新,安排重绘和控制帧速率,使用类似 Thread.sleep... 我几乎可以肯定,你已经过头了,这不会像你想象的那样奏效。您需要对线程进行一些研究。真正的问题是,你为什么认为你需要延迟?因为我保证这是错误的解决方案。 【参考方案1】:
long start = new Date().getTime();
while(new Date().getTime() - start < 1000L)

是我能想到的最简单的解决方案。

不过,堆可能会被大量未引用的 Date 对象污染,这取决于您创建此类伪延迟的频率,这可能会增加 GC 开销。

归根结底,您必须知道,与Thread.sleep() 解决方案相比,就处理器使用而言,这并不是更好的解决方案。

【讨论】:

System.currentTimeMillis 会减少 GC 问题。但这会消耗CPU周期,降低系统性能... 另外他在问题中说“没有 while 循环什么都不做”。【参考方案2】:

类似以下的内容应该可以在不阻塞游戏线程的情况下为您提供所需的延迟:

private final long PERIOD = 1000L; // Adjust to suit timing
private long lastTime = System.currentTimeMillis() - PERIOD;

public void onTick() //Called every "Tick"
    long thisTime = System.currentTimeMillis();

    if ((thisTime - lastTime) >= PERIOD) 
        lastTime = thisTime;

        if(variable)  //If my variable is true
            boolean = true; //Setting my boolean to true
            /**
            *Doing a bunch of things.
            **/
            //I need a delay for about one second here.
            boolean = false; //Setting my boolean to false;
        
    

【讨论】:

【参考方案3】:

其中一种方法是:

class Timer 
            private static final ScheduledExecutorService scheduledThreadPoolExecutor = Executors.newScheduledThreadPool(10);
    
            private static void doPause(int ms) 
                try 
                    scheduledThreadPoolExecutor.schedule(() -> 
                    , ms, TimeUnit.MILLISECONDS).get();
                 catch (Exception e) 
                    throw new RuntimeException();
                
            
        

然后您可以在需要的地方使用Timer.doPause(50)

【讨论】:

以上是关于添加一个没有 Thread.sleep 的延迟和一个啥都不做的 while 循环的主要内容,如果未能解决你的问题,请参考以下文章

android surfaceview runnable 延迟的正确方法?

JAVA中 如何使用延迟?

如何取消延迟的线程?

何时使用Task.Delay,何时使用Thread.Sleep?

使用 Thread.sleep(x) 或 wait() 时出现异常

Windows 10上的Java Thread.sleep()在S3睡眠状态下停止