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

在java中使用线程计算所用的总时间,java,multithreading,swing,Java,Multithreading,Swing,我有一个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

我有一个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:
我已经理解了这个问题:
定时器
范围就是问题所在


EDIT 2:
好的,看起来我只能在一个线程中使用
suspend
resume

您从未调用
getElapsedTime(),不是局部方法变量。此外,在线程的
run
方法中包装对
startTime
endTime
的调用并不会带来任何好处,因为这些调用的寿命非常短。但这不是真正的问题

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

您可能认为可以创建一个线程,该线程的循环在
thread.sleep(1)
之后增加
msec
变量不要这样做这种时机也是完全错误的。您的计算机使用抢占式多任务模式,这意味着无法保证您的线程将以固定间隔执行。也就是说,没有任何东西需要
线程。睡眠(1)
将睡眠一段
最长时间。保证您的线程将至少睡眠1ms。这意味着,如果您自己在软件中管理时钟,则无法确定时钟错误,并且此错误并非无关紧要不要这样做时间应该始终由操作系统测量,最好使用基于中断的计时器(这就是
system.nanoTime
在大多数平台(如果不是所有平台)上工作的方式)

不要使用线程,只需直接从原始线程调用
startTime
stopTime
方法即可

试试这个:

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应用程序,让您从web下载文件。下载文件时,更新UI中的进度条。下载应该在与UI线程分开的工作线程中进行,否则UI将在下载过程中阻塞

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

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

只需这样做

-在线程的开始处调用
System.currentTimeMillis()

-然后在线程的末尾再次调用
System.currentTimeMillis()

-
减去
以起始值结束以获得经过的时间

///EDITED/////strong>

确保试图操纵(即读写)持有
系统的
变量的
方法必须与
同步关键字
同步。currentTimeMillis()


如果您正在编写一个可能会被另一个线程读取的变量,或者正在读取一个可能上次被另一个线程写入的变量,则必须使用同步,然后,读写器必须使用相同的监视器锁进行同步。

问题在于,按下“开始”按钮会启动与按下“停止”按钮不同的
计时器对象,因为每次执行
操作时都会创建
计时器对象(…)
方法被调用

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);
         }
     }
 }

单击按钮时,您正在创建一个新的
计时器。使计时器成为
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");
            }
        }
    } 

除了旋转许多毫无意义的线程之外,完全不清楚您想要完成什么。如果您只想记录两次按键之间的时间,请将开始和结束时间保存在某个位置,并在
ActionListener
中更新它们。如果您试图创建一个不断更新的计数器,请查看
javax.swing.Timer
。如果您只是尝试学习线程,那么您应该在按下start时分叉一个线程,该线程会计算某种值。然后当按下停止键时,您可以调用
thread.interrupt()
来停止线程。@格雷:是的,我将使用
thread.interrupt()
suspend()
resume()
方法。
thread.suspend()
resume()
方法已弃用,不应使用。@Gray-这是一种非常糟糕的计时方法。有关说明,请参见下面的“我的编辑”。如果你想学习一个新的编程概念,你应该