0

I have the following code for a kind of 'stopwatch' that extends the Thread class:

package StopWatch;

//Code taken from:
//https://stackoverflow.com/questions/9526041/how-to-program-for-a-stopwatch

public class Stopwatch extends Thread {
    private long startTime;
    private boolean started;

    public void startTimer() {
        this.startTime = System.currentTimeMillis();
        this.started = true;
        this.start();
    }

    public void run() {
        while(started){/*currentTimeMillis increases on its own */}
        System.out.println("timer stopped");
    }

    public int[] getTime() {
        long milliTime = System.currentTimeMillis() - this.startTime;
        int[] time = new int[]{0,0,0,0};
        time[0] = (int)(milliTime / 3600000);    //gives number of hours elapsed
        time[1] = (int)(milliTime / 60000) % 60; //gives number of remaining minutes elapsed
        time[2] = (int)(milliTime / 1000) % 60;  //gives number of remaining seconds elapsed
        time[3] = (int)(milliTime);              //gives number of remaining milliseconds elapsed
        return time;
    }

    public void stopTimer() {
        this.started = false;
    }
}

and I'm testing it in the following driver class:

import StopWatch.Stopwatch;
public class StopWatchTest {
    public static void main(String[] args) {
        Stopwatch stopwatch = new Stopwatch();

        stopwatch.startTimer();
        int sum = 0;
        for (long i = 0; i < 100000; i++) {
            sum++;
        }
        int[] time = stopwatch.getTime();

        for (int i = 0; i < 4; i++) {
            if (i < 3) {
                System.out.print(time[i]+":");
            } else {
                System.out.print(time[i]);
            }
        }
        stopwatch.stopTimer();
    }
}

My intent is to use instances of class Stopwatch to measure the performance of various blocks of code (The for-loop in the driver class for instance) by having these Stopwatch objects in a main thread start a timer in separate thread before executing the blocks of code I want to evaluate, then have them (the Stopwatch objects) stop their timer once execution of said blocks in the main thread have finished. I understand that there are much simpler and easier ways to do this but I wanted to try doing it this way as sort of a "proof of concept" and to simply get better with multi-threading, but I'm encountering some problems:

1) When I run the driver class StopWatchTest I get seemingly random and arbitrary output each time (but mostly 0:0:0:0)

2) The main thread (or possibly the Stopwatch thread, I'm not even sure anymore) seems to never stop executing after I get outputs like 0:0:0:0

3) When I try debugging with breakpoints and the like I get completely unexpected behavior depending on where I put the breakpoints (The main thread does sometime finish execution but with random outputs like 0:0:13:2112 and other times I just get stuck in the Stopwatch thread)

Point 3 doesn't concern me as much as 1 and 2 as I have limited knowledge of how multi-threading behaves when one or several of the threads are paused at breakpoints for debugging (I suspect that when I break in the main thread the Stopwatch thread continues running). Points 1 and 2 bother me much more as I cannot see why they would be occurring.

  • since `run()` does nothing, why do you start the thread at all? It only wastes time and memory. – Alexei Kaigorodov Mar 22 '20 at 19:17
  • run() is just there to advance a timer, at least that was my intention – bmanicus131 Mar 22 '20 at 19:31
  • FYI, (a) "to measure the performance of various blocks of code" you should be using the [*Microbenchmark Suite* defined in JEP 230](https://openjdk.java.net/jeps/230), (b) "to simply get better with multi-threading" you should be using the Executors framework built into modern Java. See [Oracle Tutorials](https://docs.oracle.com/javase/tutorial/essential/concurrency/executors.html). – Basil Bourque Mar 22 '20 at 19:37
  • @bmanicus131 Since `run()` does nothing, it has no effect, and cannot advance any timer. If you mean System.currentTimeMillis(), it does not belong to any thread and ticks by hardware, no intervention is possible at all. – Alexei Kaigorodov Mar 26 '20 at 16:17

1 Answers1

1

To get you started, you should flag the boolean started as volatile:

private volatile boolean started;

That should work, but it would make a busy loop, which is very bad for your CPU usage. You should look to wait()/notify() methods next.

GeertPt
  • 16,398
  • 2
  • 37
  • 61
  • This helped! the code is now running as expected. However I'm unsure how I would use wait() and notify() to improve CPU usage here. To my knowledge wait() and notify() can only be called by objects and are used to pause/start threads that 'own' said objects. I'm not really dealing with any objects apart from stopwatch in the main thread, how would I use these here? – bmanicus131 Mar 22 '20 at 19:49
  • You could use 'this' as a monitor object, so call this.wait() in your while(started) loop and this.notify() in your stopTimer(). – GeertPt Mar 23 '20 at 08:31