计算在java中使用线程所用的总时间

时间:2012-09-12 16:20:44

标签: java multithreading swing

我有这个java代码使用Threads来计算一旦点击开始按钮直到没有按下停止按钮所经过的时间。

我想使用仅限主题

执行此操作
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:好的,看起来我只需要在一个帖子中使用suspendresume

5 个答案:

答案 0 :(得分:1)

您的问题是由timer的范围引起的。这应该是私有实例变量,而不是本地方法变量。此外,在线程的startTime方法中包含对endTimerun的调用并没有获得任何好处,因为这些是非常短暂的调用。但这不是真正的问题。

没有理由在自己的线程中运行Timer。也就是说,如果不使用专门的实时操作系统,使用线程来解决测量两个事件之间持续时间的问题就是完全错误。

您可能认为可以创建一个带有循环的线程,该循环在msec之后递增Thread.sleep(1)变量。 不要这样做!这种时机也只是错误的。您的计算机使用抢占式多任务模型,这意味着您的线程将定期执行无保证。也就是说,没有任何要求Thread.sleep(1)将在maximum个持续时间内休眠。保证您的线程将睡眠最小 1ms。这意味着如果您自己在软件中管理时钟,则无法确定时钟错误,并且此错误并非无关紧要。 只是不要这样做!! 时间应始终由您的操作系统来衡量,最好使用基于中断的计时器(这是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;
        }
    }
}

如果您想学习如何使用线程,请尝试编写一个解决问题的应用程序,以解决哪些线程非常适合。例如,编写一个允许您下载文件的小型Swing应用程序来自网络。在下载文件时,请更新UI中的进度条。下载应该在与UI线程分开的工作线程中进行,否则UI将在下载过程中阻止。

另一个示例问题是编写一个线程光线跟踪器(这里是用C ++编写的example tutorial)。

如果你想要更简单的东西,可以写一个Swing时钟。在单独的线程中使用循环以定期间隔更新UI,但使用循环来管理它的时间。同样,不要试图在循环中保持时间,只是让操作系统保留时间,并使用循环来安排UI何时使用当前操作系统时间进行更新。

答案 1 :(得分:1)

问题是按下启动按钮是为了启动不同的 Timer对象而不是按停止按钮按钮,因为每次都会创建Timer对象调用actionPerformed(...)方法。

Timer必须是MyAction课程中的字段。您也不需要所有的线程启动/连接,因为Timer对象非常简单快速。

实际上,您可以使用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);
         }
     }
 }

答案 2 :(得分:0)

您永远不会致电更新getElapsedTime()字段的elapsed

答案 3 :(得分:0)

只需这样做......

- 线程开始时致电System.currentTimeMillis()

- 然后再次在结束时调用System.currentTimeMillis()

- Subtract结束时的起始值可以获得经过的时间......

<强> ///////////////// EDITED ///////////////////////

确保method试图操纵(即读取和写入)持有variable的{​​{1}}必须与System.currentTimeMillis()同步,以便竞争条件根据{{​​1}} ...

不会发生

synchronized keyword

答案 4 :(得分: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");
            }
        }
    }