如何从吃掉> 50%的CPU中停止Java循环?

时间:2009-02-24 03:54:41

标签: java loops cpu-usage

好吧,我在一个空程序上测试了这个,只是运行一段时间(真实){}让我在CPU上运行了50%。我有一个我正在使用的游戏,它使用while循环作为它的主循环,并且它的CPU始终为100。

我怎样才能让Java一遍又一遍地重复一遍而不吃掉> 50%的CPU只是为了重复?

9 个答案:

答案 0 :(得分:42)

添加一个睡眠以使线程空闲一段时间:

Thread.sleep

没有睡眠,while循环将消耗所有可用的计算资源。 (例如,理论上,单核系统中100%,双核中50%,等等。)

例如,以下内容将大约每50毫秒循环一次while循环:

while (true)
{
    try
    {
        Thread.sleep(50);
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

这应该会降低CPU利用率。

在循环中休眠时,操作系统还将为其他线程和进程提供足够的系统时间来执行操作,因此系统也会响应。在具有不太好的调度程序的单核系统和操作系统的时代,像这样的循环可能使系统反应迟钝。


由于游戏的while循环的使用主题出现了,如果游戏涉及到GUI,游戏循环必须在一个单独的线程中,否则GUI本身将无法响应。< / p>

如果程序将成为基于控制台的游戏,那么线程不会成为问题,但是对于事件驱动的图形用户界面,在代码中具有长寿命循环将使GUI成为可能不响应。

线程等等是非常棘手的编程领域,特别是在入门时,所以我建议在必要时提出另一个问题。

以下是基于JFrame的Swing应用程序示例,该应用程序更新将包含JLabel返回值的System.currentTimeMillis。更新过程在一个单独的线程中进行,“停止”按钮将停止更新线程。

示例中很少有概念说明:

  • 基于Swing的GUI应用程序,具有单独的线程来更新时间 - 这将防止GUI线程的锁定。 (在Swing中称为EDT或事件派发线程。)
  • while循环的循环条件不是true,而是用boolean代替,这将决定是否保持循环活动。
  • Thread.sleep如何影响实际应用程序。

请原谅我这个长长的例子:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class TimeUpdate
{
    public void makeGUI()
    {
        final JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final JLabel l = new JLabel();

        class UpdateThread implements Runnable
        {
            // Boolean used to keep the update loop alive.
            boolean running = true;

            public void run()
            {
                // Typically want to have a way to get out of
                // a loop. Setting running to false will 
                // stop the loop.
                while (running)
                {
                    try
                    {
                        l.setText("Time: " +
                                System.currentTimeMillis());

                        Thread.sleep(50);
                    }
                    catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }

                // Once the run method exits, this thread
                // will terminate.
            }
        }

        // Start a new time update thread.
        final UpdateThread t = new UpdateThread();
        new Thread(t).start();

        final JButton b = new JButton("Stop");
        b.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                t.running = false;
            }
        });

        // Prepare the frame.
        f.getContentPane().setLayout(new BorderLayout());
        f.getContentPane().add(l, BorderLayout.CENTER);
        f.getContentPane().add(b, BorderLayout.SOUTH);
        f.setLocation(100, 100);
        f.pack();
        f.setVisible(true);
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new TimeUpdate().makeGUI();
            }
        });
    }
}

有关线程和使用Swing的一些资源:

答案 1 :(得分:29)

Thread.Sleep可能不是完整的答案。对于大多数游戏来说,CPU所需的工作量太多了。简单地睡一段时间并不是那么有效,因为你可能仍然会烧掉太多的资源,或者说不够。您通常希望以某种方式计算您的工作时间。

如果您考虑一下,屏幕只会以一定的速率更新,通常每秒少于100次。我对这种事情并不熟悉Java api,但你想要的是找出监视器的刷新速度,然后在每次刷新之间只更新一次。

此外,您不需要像主循环那样的循环,您可以使用计时器定期调用更新代码。这样效率更高。

答案 2 :(得分:10)

你确实在忙着等待,这意味着你要经常检查一个或多个条件,直到它们成真为止。

Thread.sleep() 不是解决方案。使用wait()notify()方法可以让您完成正在尝试的内容,但效率更高。基本上,这种机制允许一个线程在一个对象上休眠,直到该对象决定发生了什么并且想要唤醒所有在它上面休眠的线程。

可以找到代码exmaples herehere.

这个应该是你的解决方案,而不是用计时器隐藏你的忙等待。

答案 3 :(得分:6)

通常在游戏循环中,您会暂停一下......例如:http://developers.sun.com/mobility/midp/articles/game/

答案 4 :(得分:6)

虽然是,但你可以做一个

Thread.sleep(50)

就像接受的答案建议一样,你也可以打电话给

Thread.sleep(0) 

这将告诉处理器进行上下文切换。等待执行的其他线程(如GUI绘图线程)将被执行,机器将停止感觉缓慢。

sleep(0)方式也会最大化操作系统给你的应用程序的时间,因为线程会立即回到处理器的队列中(而不是等待50ms才这样做)所以如果没有其他线程在等待,你线程将继续执行。

答案 5 :(得分:0)

好像你的线程忙着等待。也就是说,它被困在一个它什么都不做的循环中。在这种情况下,它会咀嚼很多cpu周期而没有效果。

正如其他人所说,Thread.sleep就是答案。

答案 6 :(得分:0)

That's swing-related,但想法保持不变:尝试使用观察者模式而不是wile(true)

答案 7 :(得分:0)

基于Quartz-Spring的调度程序如何在重复的时间间隔内一遍又一遍地完成工作。

答案 8 :(得分:0)

如果有中断,可能是有原因的。处理此问题的更好方法是

try {
    while (true) {
        Thread.sleep(50);
    }
} catch (InterruptException e) {
    Thread.currentThread().interrupt();
}

但是这个循环没有做任何事情,所以我建议你删除它。你想要忙于等待一个条件是很少见的(在这种情况下,Condition类是一个更好的选择)通常你可以转换相同的行为而不需要一个循环。