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

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

我怎样才能让Java一遍又一遍地重复一些事情而不吃掉超过50%的CPU来做重复?

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

Thread.sleep

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

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

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

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

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


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

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

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

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

这个例子很少说明:

  • 基于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的一些资源:

  • 线程和Swing
  • 课程:并发

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

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

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

你确实忙着等待,这意味着你在检查一个或多个条件时不断研磨CPU,直到它们成立为止。

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

代码exmaples可以在这里和这里找到。

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

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

虽然是的,你可以做一个

 Thread.sleep(50) 

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

 Thread.sleep(0) 

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

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

看起来你的线程正在忙着等待。 也就是说,它被困在一个它什么都不做的循环中。 在这种情况下,它会咀嚼很多cpu周期而不起作用。

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

这与摇摆有关 ,但这个想法保持不变:尝试使用Observer模式而不是wile(true)

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

如果有中断,可能是有原因的。 处理这个的更好方法是

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

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