Ian Campbell
Ian Campbell

Reputation: 2748

How to make a stopwatch as a thread in Java?


I am trying to implement a stopwatch similar to that found at Is there a stopwatch in Java?, but as a Thread.

My SecondsCounter class implements Runnable, and invoking its' start method will then create a thread as a local variable.

It would seem as if this thread is conflicting with the first line in the run method:  this.runningTime = System.currentTimeMillis(); ...because the condition while (this.runningTime < this.endTime) is never broken (an infinite loop)...

So is it incorrect to have a class that both implements Runnable and contains its' Thread as well?



Here is the class with the main method:

public class MultithreadingTest {

    public static void main(String[] args) {
        int totalSeconds = 5;
        SecondsPrinter printer = new SecondsPrinter(totalSeconds);
        printer.startPrinting();
    }
} // end of class


...the seconds printer class:

public class SecondsPrinter {

    // composition here:
    private SecondsCounter clock;

    public SecondsPrinter(int totalSeconds) {
        this.clock = new SecondsCounter(totalSeconds);
    }

    public void startPrinting() {
        this.clock.start();
        while (this.clock.isRunning()) {

            // this is incorrectly always printing the maximum seconds value:
            System.out.println(this.clock.getCurrentSecond());
        }
    }
} // end of class


...and the seconds counter class:

public class SecondsCounter implements Runnable {

    private int totalSeconds, currentSecond;
    private long startTime, runningTime, endTime;
    private Thread thread;

    public SecondsCounter(int totalSeconds) {
        this.totalSeconds = totalSeconds;
    }

    public int getCurrentSecond() {
        return this.currentSecond;
    }

    @Override
    public void run() {
        this.runningTime = System.currentTimeMillis();

        // this is an infinite loop, but it shouldn't be:
        while (this.runningTime < this.endTime) {
            this.currentSecond = (int)(this.endTime - this.runningTime) / 1000;
        }

        // this code is never reached:
        this.stop();
    }

    public void start() {
        this.startTime = System.currentTimeMillis();
        this.runningTime = this.startTime;
        this.endTime = this.startTime + (this.totalSeconds * 1000);

        // multithreading here:
        this.thread = new Thread(this);
        this.thread.start();
    }

    public boolean isRunning() {
        return this.thread.isAlive();
    }

    public void stop() {
        this.thread.interrupt();
        this.thread = null;
    }
} // end of class

Upvotes: 2

Views: 8276

Answers (1)

Justin
Justin

Reputation: 25297

Actually, that should be an infinite loop. Look at your loop.

while (this.runningTime < this.endTime) {
    this.currentSecond = (int)(this.endTime - this.runningTime) / 1000;
}

The condition says that it will loop while runningTime < endTime. Where is runningTime updated? If you add something like this to the loop, it should work:

public void run() {
    this.runningTime = System.currentTimeMillis();

    // no longer an infinite loop
    while (this.runningTime < this.endTime) {
        this.currentSecond = (int)(this.endTime - this.runningTime) / 1000;
        this.runningTime = System.currentTimeMillis();
    }

    // this code is now reached.
    this.stop();
}

You could even combine it (or remove the variable runningTime altogether):

public void run() {
    while ((this.runningTime = System.currentTimeMillis()) < this.endTime) {
        this.currentSecond = (int)(this.endTime - this.runningTime) / 1000;
    }

    this.stop();
}

Upvotes: 4

Related Questions