20

これを空のプログラムでテストしたところ、while(true){} を実行しただけで CPU 使用率が 50% を超えました。メイン ループとして while ループを使用するゲームに取り組んでおり、CPU は常に 100 です。

繰り返しを行うためだけに CPU の 50% を超えて消費することなく、Java に何かを何度も繰り返させるにはどうすればよいですか?

4

9 に答える 9

44

スリープを追加して、スレッドを一定期間アイドル状態にします。

Thread.sleep

スリープしないと、while ループは利用可能なすべてのコンピューティング リソースを消費します。(たとえば、理論的には、シングル コア システムで 100%、デュアル コア システムで 50% など)。

たとえば、次の例では、while約 50 ミリ秒ごとにループを 1 回循環します。

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

これにより、CPU 使用率がかなり低下するはずです。

ループ内のスリープにより、オペレーティング システムは、他のスレッドやプロセスが処理を行うのに十分なシステム時間を与えるため、システムも応答します。シングル コア システムやあまり良くないスケジューラーを備えたオペレーティング システムの時代には、このようなループによってシステムが非常に応答しなくなる可能性がありました。


ゲームでループを使用するという話題がwhile出てきたので、ゲームに GUI が含まれる場合、ゲーム ループは別のスレッドにある必要があります。そうしないと、GUI 自体が応答しなくなります。

プログラムがコンソール ベースのゲームになる場合、スレッド化は問題になりませんが、イベント ドリブンのグラフィカル ユーザー インターフェイスでは、コード内に長寿命のループがあると、GUI が応答しなくなります。

スレッド化などはプログラミングのかなり難しい領域であり、特に始めたばかりのときはそうです。そのため、必要になったときに別の問題を提起することをお勧めします。

以下は、からの戻り値を含むJFrameを更新する に基づく Swing アプリケーションの例です。更新プロセスは別のスレッドで行われ、「停止」ボタンは更新スレッドを停止します。JLabelSystem.currentTimeMillis

この例で説明するいくつかの概念:

  • 時間を更新する別のスレッドを持つ Swing ベースの GUI アプリケーション -- これにより、GUI スレッドのロックアップが防止されます。(EDT、または Swing ではイベント ディスパッチ スレッドと呼ばれます。)
  • whileではないループ条件を持つループを持つが、ループを維持するかどうかを決定するtruea に置き換えられます。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 の使用に関するリソース:

于 2009-02-24T03:57:21.887 に答える
29

Thread.Sleep がすべての答えではないかもしれません。ほとんどのゲームでは、必要な作業量に対して CPU が多すぎます。一定時間スリープするだけではあまり効率的ではありません. 通常、何らかの方法で作業の時間を計ります。

考えてみると、画面は一定の速度でしか更新されず、通常は 1 秒あたり 100 回未満です。私はこの種の Java API に精通していませんが、モニターの更新速度を調べて、更新ごとに 1 回だけ更新する必要があります。

さらに、メインループにそのようなループは必要ありません。タイマーを使用して定期的に更新コードを呼び出すことができます。これはさらに効率的です。

于 2009-02-24T05:21:33.433 に答える
12

あなたは確かに忙しいのを待っています。つまり、1つまたは複数の条件が真になるまで、CPUを常にチェックしているということです。

Thread.sleep() 解決策ではありませんwait()およびメソッドを使用notify()すると、試行していることを実行できますが、はるかに効率的です。基本的に、このメカニズムでは、オブジェクトが何かが起こったと判断し、その上でスリープしているすべてのスレッドをスリープ解除するまで、スレッドをオブジェクト上でスリープさせることができます。

コードの例はここここにあります。

これはあなたの解決策であるべきであり、あなたの忙しい時間を隠さないでください-タイマーで待ってください。

于 2009-02-24T07:58:20.310 に答える
7

はい、あなたはすることができます

Thread.sleep(50)

受け入れられた回答が示唆するように、電話することもできます

Thread.sleep(0) 

これにより、プロセッサはコンテキスト スイッチを実行するように指示されます。実行を待機している他のスレッド (GUI 描画スレッドなど) が実行され、マシンが遅く感じなくなります。

sleep(0) 方法は、OS からアプリケーションに与えられる時間を最大化します。これは、スレッドがすぐにプロセッサのキューに戻るため (そうする前に 50 ミリ秒待機するのではなく)、他のスレッドが待機していない場合、スレッドは続行します実行中。

于 2009-02-24T20:50:59.300 に答える
6

通常、ゲーム ループでは少し一時停止します。例: http://developers.sun.com/mobility/midp/articles/game/

于 2009-02-24T03:58:38.467 に答える
0

これはスイングに関連していますが、考え方は同じです。の代わりにObserverパターンを使用してみてくださいwile(true)

于 2009-02-24T07:50:33.450 に答える
0

繰り返しの間隔で何度も何度も作業を続ける Quartz-Spring ベースのスケジューラはどうですか。

于 2009-02-24T11:11:25.293 に答える
0

あなたのスレッドはビジーウェイティングしているようです。つまり何もしないループに陥っている。このような状況では、多くの CPU サイクルを食いつぶして効果がありません。

他の人が述べたように、 Thread.sleep が答えです。

于 2009-02-24T03:59:07.903 に答える