如何阻止 Java while 循环占用>50% 的 CPU?

2022-09-02 04:57:32

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

我怎样才能让Java一遍又一遍地重复一些事情,而不会消耗掉>50%的CPU来执行重复?


答案 1

添加一个睡眠以将线程置于空闲状态一段时间:

Thread.sleep

如果没有休眠状态,while 循环将消耗所有可用的计算资源。(例如,从理论上讲,单核系统中为 100%,双核系统中为 50%,依此类推。

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

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

这应该会大大降低CPU利用率。

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


由于出现了游戏使用循环的主题,因此如果游戏将涉及GUI,则游戏循环必须位于单独的线程中,否则GUI本身将变得无响应。while

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

线程化等是编程中非常棘手的领域,尤其是在入门时,因此我建议在必要时提出另一个问题。

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

该示例将说明的几个概念:

  • 基于 Swing 的 GUI 应用程序具有单独的更新时间线程 -- 这将防止锁定 GUI 线程。(称为 EDT,或在 Swing 中称为事件调度线程。
  • 让循环条件不是 ,但用 a 代替,将决定是否保持循环处于活动状态。whiletrueboolean
  • 如何影响实际应用。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 的一些资源:


答案 2

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

如果您考虑一下,屏幕仅以一定的速率更新,通常每秒不到100次。我不熟悉Java API的这种事情,但你想要的是找出显示器的刷新速度,然后在每次刷新之间只更新一次。

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


推荐