有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用java中的线程计算总运行时间的多线程处理

我有一个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:好的,看起来我只能在一个线程中使用suspendresume


共 (5) 个答案

  1. # 1 楼答案

    问题是,start button press启动的对象与stop button press停止的对象不同,因为每次调用actionPerformed(...)方法时都会创建Timer对象

    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. # 2 楼答案

    单击按钮时,您正在创建一个新的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");
                }
            }
        } 
    
  3. # 3 楼答案

    您的问题是由timer的范围引起的这应该是一个私有实例变量,而不是局部方法变量。此外,在线程的run方法中包装对startTimeendTime的调用并没有带来任何好处,因为这些调用的寿命非常短。但这不是这里真正的问题

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

    您可能认为可以创建一个线程,该线程的循环在Thread.sleep(1)之后增加一个msec变量不要这样做这种时间安排也显然是错误的。您的计算机使用抢先多任务模式,这意味着不能保证线程会定期执行。也就是说,没有什么需要Thread.sleep(1)睡眠一段时间。保证您的线程将至少睡眠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应用程序,让您从web下载文件。下载文件时,更新UI中的进度条。下载应该在与UI线程分开的工作线程中进行,否则UI将在下载过程中阻塞

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

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

  4. # 4 楼答案

    只要这样做

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

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

    -Subtract以起始值结束以获取经过的时间

    /////EDITED/////////strong>

    确保试图操纵(即读写)持有System.currentTimeMillis()method必须与synchronized keyword同步,以便根据Brian'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.

  5. # 5 楼答案

    您从未调用过更新elapsed字段的getElapsedTime()