如何阻止 Java while 循环占用超过 50% 的 CPU?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/580419/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I stop a Java while loop from eating >50% of my CPU?
提问by William
Okay, I tested this on an empty program, and just having a while(true){} running gave me >50% on my CPU. I have a game I'm working on that uses a while loop as it's main loop, and it's CPU is at 100 all the time.
好的,我在一个空程序上对此进行了测试,只要运行一段时间 (true){},我的 CPU 就会超过 50%。我正在开发一个游戏,它使用 while 循环作为主循环,并且它的 CPU 始终为 100。
How can I get Java to repeat something over and over without eating up >50% of my CPU just to do the repeating?
我怎样才能让 Java 一遍又一遍地重复某些事情,而不会为了重复而消耗超过 50% 的 CPU?
回答by coobird
Add a sleep to put the thread into idle for some interval:
添加 sleep 以使线程在一段时间内处于空闲状态:
Without having a sleep, the while loop will consume all the computing resources that is available. (For example, theoretically, 100% in a single core system, or 50% in a dual core, and so on.)
在没有睡眠的情况下,while 循环将消耗所有可用的计算资源。(例如,理论上,单核系统中为 100%,或双核中为 50%,依此类推。)
For example, the following will cycle once through a whileloop approximately every 50 milliseconds:
例如,以下内容将while大约每 50 毫秒循环一次:
while (true)
{
try
{
Thread.sleep(50);
}
catch (Exception e)
{
e.printStackTrace();
}
}
This should bring down the CPU utilization quite a bit.
这应该会大大降低 CPU 利用率。
With a sleep in the loop, the operating system will also give enough system time for other threads and processes to do their things, so the system will be responsive as well. Back in the days of single core systems and operating systems with not-so-good schedulers, loops like this could have made the system very unresponsive.
通过循环睡眠,操作系统还会为其他线程和进程提供足够的系统时间来完成它们的工作,因此系统也会做出响应。回到具有不太好的调度程序的单核系统和操作系统的时代,像这样的循环可能会使系统非常无响应。
Since the topic of use of whileloops for a game came up, if the game is going to involve a GUI, the game loop must be in a separate thread or else the GUI itself will become unresponsive.
由于while出现了在游戏中使用循环的话题,如果游戏将涉及 GUI,则游戏循环必须在单独的线程中,否则 GUI 本身将变得无响应。
If the program is going to be a console-based game, then threading is not going to be an issue, but with graphical user interfaces which are event-driven, having a long-living loop in the code will make the GUI unresponsive.
如果程序将是基于控制台的游戏,那么线程不会成为问题,但是对于事件驱动的图形用户界面,代码中的长期循环将使 GUI 无响应。
Threading and such are pretty tricky areas of programming, especially when getting started, so I suggest that another question be raised when it becomes necessary.
线程等是非常棘手的编程领域,尤其是在开始时,所以我建议在必要时提出另一个问题。
The following is an example of a Swing application based in a JFramewhich updates a JLabelthat will contain the returned value from System.currentTimeMillis. The updating process takes place in a separate thread, and a "Stop" button will stop the update thread.
下面是一个基于 a 的 Swing 应用程序的示例,JFrame它更新了 a JLabel,其中将包含来自 的返回值System.currentTimeMillis。更新过程发生在一个单独的线程中,“停止”按钮将停止更新线程。
Few concepts the example will illustrate:
该示例将说明的几个概念:
- A Swing-based GUI application with a separate thread to update time -- This will prevent lock up of the GUI thread. (Called the EDT, or event dispatch thread in Swing.)
- Having the
whileloop with a loop condition that is nottrue, but substituted with abooleanwhich will determine whether to keep the loop alive. - How
Thread.sleepfactors into an actual application.
- 基于 Swing 的 GUI 应用程序有一个单独的线程来更新时间——这将防止 GUI 线程的锁定。(在 Swing 中称为 EDT 或事件调度线程。)
- 使
while循环的循环条件不是true,而是用 a 代替,boolean这将确定是否使循环保持活动状态。 - 如何
Thread.sleep影响实际应用。
Please excuse me for the long example:
请原谅我的长示例:
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();
}
});
}
}
Some resources about threading and using Swing:
关于线程和使用 Swing 的一些资源:
回答by Erik Funkenbusch
Thread.Sleep may not be the whole answer. For most games, there's way too much CPU for the amount of work needed. Simply sleeping for a set amount of time isn't all that efficient, since you will likely either still burn too many resources, or not enough. You typically want to time your work in some way.
Thread.Sleep 可能不是全部答案。对于大多数游戏来说,CPU 数量太多,无法满足所需的工作量。简单地睡一段时间并不是那么有效,因为你可能仍然会消耗太多资源,或者不够。您通常希望以某种方式为您的工作计时。
If you think about it, the screen only updates at a certain rate, typically less than 100 times per second. I'm not familiar with the Java api's for this sort of thing, but what you want is to find out the refresh speed of the monitor and then update only a single time between each refresh.
仔细想想,屏幕只会以一定的速度更新,通常每秒不到 100 次。我不熟悉用于此类事情的 Java api,但是您想要的是找出监视器的刷新速度,然后在每次刷新之间仅更新一次。
Further, you don't need a loop like that for your main loop, you can use timers to call your update code at a regular interval. This is even more efficient.
此外,您不需要像主循环那样的循环,您可以使用计时器定期调用更新代码。这样效率更高。
回答by Yuval Adam
You are indeed busy-waiting, meaning you are grinding your CPU constantly on checking one or more conditions until they are true.
您确实在忙于等待,这意味着您一直在检查一个或多个条件,直到它们为真为止,从而不断磨削 CPU。
Thread.sleep()is notthe solution. Using wait()and notify()methods allows you to do just what you are trying, but much more efficiently. Basically, this mechanism allows a thread to sleep on an object until the object decides something has happened and wants to wake all the threads sleeping on it.
Thread.sleep()不是解决办法。使用wait()和notify()方法可以让你做你正在尝试的事情,但效率更高。基本上,这种机制允许线程在对象上休眠,直到对象决定发生了某些事情并想要唤醒所有在其上休眠的线程。
Code exmaples can be found hereand here.
Thisshould be your solution, and not hiding your busy-wait with a timer.
这应该是您的解决方案,而不是用计时器隐藏您的忙碌等待。
回答by Frederic Morin
While yes, you could do a
虽然是的,你可以做一个
Thread.sleep(50)
like the accepted answer suggest, you could also call
就像接受的答案建议一样,你也可以打电话
Thread.sleep(0)
This will tell the processor to do a context switch. Other threads waiting to be executed (like the GUI drawing thread) will then be executed and the machine will stop feeling slow.
这将告诉处理器进行上下文切换。其他等待执行的线程(如 GUI 绘图线程)将被执行,机器将停止感觉缓慢。
The sleep(0) way will also maximise the time given by the OS to you application because the thread will immediatly go back in the processor's queue (instead of waiting 50ms before doing so) so if no other thread where waiting, you thread will continue being executed.
sleep(0) 方式还将最大化操作系统为您的应用程序提供的时间,因为线程将立即返回处理器的队列(而不是在此之前等待 50 毫秒),因此如果没有其他线程在等待,您的线程将继续被处决。
回答by TofuBeer
Usually in a game loop you will pause for a bit... for example: http://developers.sun.com/mobility/midp/articles/game/
通常在游戏循环中你会暂停一下......例如:http: //developers.sun.com/mobility/midp/articles/game/
回答by Rob Lachlan
It seems like your thread is busywaiting. That is to say, it is trapped in a loop in which it does nothing. In such a situation, it will chew up a lot of cpu cycles to no effect.
好像您的线程正在忙于等待。也就是说,它被困在一个什么都不做的循环中。在这种情况下,它会消耗很多 cpu 周期而无效。
As mentioned by others, Thread.sleep is the answer.
正如其他人所提到的,Thread.sleep 就是答案。
回答by yanchenko
That's swing-related, but the idea stays the same: try to use Observer pattern instead of wile(true).
这与 swing 相关,但想法保持不变:尝试使用 Observer 模式而不是wile(true).
回答by Peter Lawrey
If there is an interrupt it is probably for a reason. A better way to handle this is
如果有中断,那可能是有原因的。处理这个问题的更好方法是
try {
while (true) {
Thread.sleep(50);
}
} catch (InterruptException e) {
Thread.currentThread().interrupt();
}
However this loop doesn't do anything, so I suggest you just delete it. It is fairly rare that you want to busy wait for a condition (In which case the Condition class is a better choice) usually you can transform the same behaviour not to need a loop at all.
但是这个循环没有做任何事情,所以我建议你删除它。您想忙于等待条件(在这种情况下 Condition 类是更好的选择)的情况很少见,通常您可以将相同的行为转换为根本不需要循环。
回答by Franklin
How about a Quartz-Spring based scheduler that keeps doing the work over and over again in repeated intervals.
基于 Quartz-Spring 的调度器如何以重复的时间间隔一遍又一遍地执行工作。

