1

スレッドを使用して、開始ボタンが押されてから停止ボタンが押されなくなるまでの経過時間を計算するこのJavaコードがあります。

スレッドのみを使用してこれを実行したい

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

// This will count the elapsed time between running time of two threads.
class ThreadGame {

    JButton button;
    MyAction my_action;

    public static void main(String[] args) {
        ThreadGame tg = new ThreadGame();
    }

    public ThreadGame() {
        JFrame frame = new JFrame("Calculate time - Game");
        button = new JButton("Start");
        button.addActionListener(new MyAction());
        frame.add(button);
        frame.setSize(400, 400);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    class MyAction implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            String text = (String) e.getActionCommand();

            final Timer timer = new Timer();

            if (text.equals("Start")) {
                button.setText("Stop");

                Thread start_time = new Thread() {
                    public void run() {
                        timer.startTime();
                    }
                };

                start_time.start();
                try {
                    start_time.join();
                } catch (Exception e1) {
                }

            } else {
                Thread stop_time = new Thread() {
                    public void run() {
                        timer.stopTime();
                    }
                };

                Thread get_time = new Thread() {
                    public void run() {
                        timer.getElapsedTime();
                        System.out.println(timer.elapsed);
                    }
                };
                stop_time.start();
                try {
                    stop_time.join();
                } catch (Exception e2) {
                }

                get_time.start();

                button.setText("Start");
            }
        }
    }

    class Timer {
        public double startTime = 0.0;
        public double stopTime = 0.0;
        public boolean running = false;
        public double elapsed = 0.0;

        public void startTime() {
            this.startTime = System.nanoTime();
            this.running = true;
        }

        public void stopTime() {
            this.stopTime = System.nanoTime();
            this.running = false;
        }

        // Elasped time in seconds
        public double getElapsedTime() {
            // double elapsed;
            if (running) {
                elapsed = ((System.nanoTime() - startTime) / 1000);
            } else {
                elapsed = ((stopTime - startTime) / 1000);
            }
            return elapsed;
        }
    }
}

EDIT:私は問題を理解しました:timerスコープが問題でした。

EDIT 2:わかりました。1つのスレッドでのみsuspend使用する必要があるようです。resume

4

5 に答える 5

1

問題は、メソッドが呼び出されるたびにオブジェクトが作成されるため、開始ボタンを押すと停止ボタンを押すのとは異なるオブジェクトが開始されることです。 TimerTimeractionPerformed(...)

クラスのTimerフィールドである必要がありますMyActionTimerオブジェクトは非常に単純で高速であるため、すべてのスレッドの開始/結合も必要ありません。

startTimeMillis実際、タイマーの代わりに長いフィールドを使用できます。何かのようなもの:

class MyAction implements ActionListener {
   private long startTimeMillis;
   public void actionPerformed(ActionEvent e) {
        String text = (String) e.getActionCommand();

        if (text.equals("Start")) {
            startTimeMillis = System.currentTimeMillis();
            ...
         } else {
            System.out.println(System.currentTimeMillis() - startTimeMillis);
         }
     }
 }
于 2012-09-12T16:31:25.713 に答える
1

あなたの問題は の範囲が原因ですtimer これは、ローカル メソッド変数ではなく、プライベート インスタンス変数である必要があります。startTimeさらに、スレッドのメソッドへの呼び出しとendTimeスレッドのメソッド内での呼び出しをラップしrunても、何も得られません。しかし、それはここでの本当の問題ではありません。

Timer独自のスレッドで実行する理由はありません。つまり、専用のリアルタイム オペレーティング システムを使用せずに、スレッドを使用して 2 つのイベント間の期間を測定するという問題を解決することは、まったく間違っています。

msecの後に変数をインクリメントするループを含むスレッドを作成できると考えるかもしれませんThread.sleep(1)これをしないでください! この種のタイミングも明らかに間違っています。お使いのコンピューターはプリエンプティブ マルチタスク モデルを使用しています。つまり、スレッドが定期的に実行されるという保証はありません。つまり、一定期間Thread.sleep(1)スリープする必要はありません。maximum保証は、スレッドが最低1ミリ秒スリープすることです。これは、ソフトウェアでクロックを自分で管理している場合、クロック エラーを判断する方法がないことを意味し、このエラーは重要ではありません。 やらないでください!時間は常にオペレーティング システムで測定する必要があります。できれば割り込みベースのタイマーを使用してください (これはSystem.nanoTime、すべてのプラットフォームではないにしても、ほとんどのプラットフォームで機能します)。

スレッドを使用する代わりに、元のスレッドからメソッドstartTimestopTimeメソッドを直接呼び出すだけです。

これを試して:

class ThreadGame {

    JButton button;
    MyAction my_action;
    private final Timer timer = new Timer();

    public static void main(String[] args) {
        ThreadGame tg = new ThreadGame();
    }

    public ThreadGame() {
        JFrame frame = new JFrame("Calculate time - Game");
        button = new JButton("Start");
        button.addActionListener(new MyAction());
        frame.add(button);
        frame.setSize(400, 400);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    class MyAction implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            String text = (String) e.getActionCommand();

            if (text.equals("Start")) {
                timer.startTime();
                button.setText("Stop");
            } else {
                timer.stopTime();
                button.setText("Start");
            }
        }
    }

    class Timer {
        public double startTime = 0.0;
        public double stopTime = 0.0;
        public boolean running = false;
        public double elapsed = 0.0;

        public void startTime() {
            this.startTime = System.nanoTime();
            this.running = true;
        }

        public void stopTime() {
            this.stopTime = System.nanoTime();
            this.running = false;
        }

        // Elasped time in seconds
        public double getElapsedTime() {
            return (this.startTime-this.stopTime)*1000000000.0;
        }
    }
}

スレッドの使用方法を学びたい場合は、スレッドが適している問題を解決するアプリケーションを作成してみてください。 たとえば、Web からファイルをダウンロードできる小さな Swing アプリケーションを作成します。ファイルのダウンロード中に、UI の進行状況バーを更新します。ダウンロードは、UI スレッドとは別にワーカー スレッドで実行する必要があります。そうしないと、ダウンロードの進行中に UI がブロックされます。

もう 1 つの問題の例は、スレッド化されたレイ トレーサーを作成することです ( C++ で作成されたチュートリアルの例を次に示します)。

より単純なものが必要な場合は、Swing クロックを記述します。別のスレッド内でループを使用して UI を定期的に更新しますが、ループを使用して時間を管理しないでください。繰り返しますが、ループで時間を保持しようとしないでください。OS に時間を保持させ、ループを使用して、UI が現在の OS 時間で更新されるタイミングをスケジュールします。

于 2012-09-12T16:24:33.133 に答える
0

getElapsedTime()その更新elapsedフィールドを呼び出すことは決してありません。

于 2012-09-12T16:24:01.757 に答える
0

これを行うだけで...

-スレッドSystem.currentTimeMillis()の開始時に呼び出します。

-次に、スレッドSystem.currentTimeMillis()の最後で再度呼び出します。

- Subtract経過時間を取得するための開始値で終了...

/////////////////編集済み//////////////////////

競合状態が発生しないように、method操作 (つまり、読み取りと書き込み) をvariable保持しているSystem.currentTimeMillis()を と同期する必要があることを確認してください...synchronized keywordBrian's Law

If you are writing a variable that might next be read by another thread, or reading a variable that might have last been written by another thread, you must use synchronization, and further, both the reader and the writer must synchronize using the same monitor lock.

于 2012-09-12T16:27:51.677 に答える
0

ボタンをクリックするたびに、新しいものを作成してTimerいます。タイマーをあなたのクラス変数にしますMyAction

経過時間を取得するには、以下のコードで十分です。

    class MyAction implements ActionListener {
        final Timer timer = new Timer();            
        public void actionPerformed(ActionEvent e) {
            String text = (String) e.getActionCommand();                
            if (text.equals("Start")) {
                button.setText("Stop");
                timer.startTime();
            } else {
                timer.stopTime();
                System.out.println(timer.elapsed);
                button.setText("Start");
            }
        }
    } 
于 2012-09-12T16:34:07.503 に答える