Java how to write a timer

I wanted to write a timer in java.which will do the following: when program starts,start the timer1 which will stop after 45 mins, at the same time start the second timer, which will stop after 15 mins. at this time the first timer will starts again, and repeat the above loop until the program exits first timer : 45 min (the time I can use computer) second timer: 15 min (the pause time) first timer : 45 min (the time I can use computer) second timer: 15 min (the pause time) first timer : 45 min (the time I can use computer) second timer: 15 min (the pause time)

I dont know how to use the thread and timer (utils,swing) so I tried to use while(true) but the cpu goes up. here is my current code

static int getMinute(){
    Calendar cal=Calendar.getInstance();
    int minute=cal.getTime().getMinutes();
    return minute;
}

public static Runnable clockf(){
    if (endTime>=60){
        endTime=endTime-60;}
    System.out.println(startTime);
    System.out.println(currentTime);
    System.out.println(endTime);

    if(currentTime==endTime){
        pauseStart=getMinute();
        currentTime=getMinute();
        pauseEnd=pauseStart+15;

        if(currentTime==pauseEnd){
            pauseStart=0;
            pauseEnd=0;
            startTime=getMinute();
            currentTime=getMinute();
            endTime=startTime+45;
        }
    }
    else{
        update();
    }

    return null;

}

private static void update() {
    currentTime=getMinute();
    System.out.println(currentTime);
}

public static void main(String[] args) {
    startTime=getMinute();
    currentTime=getMinute();
    endTime=startTime+45;

    Thread t=new Thread(clockf());
    t.setDaemon(true);
    t.start();
    try {
        Thread.currentThread().sleep(1000);//60000

    } catch (InterruptedException e) {
        System.err.println(e);
    }



    }

but it isnt good. are there any way to make the clockf method run only once / min ? or any other way to make that timer runs ?

Even though I did not fully understand what you're trying to do Timer and TimerTask should do that for you. Following code has to improved a bit to be runnable, but hopefully shows the principle:

long minute = 1000*60;

Timer timer1 = new Timer();
long delay1 = 45*minute;
Timer timer2 = new Timer();
long delay2 = 15*minute;
TimerTask tt1;
TimerTask tt2;

...

tt1 = new TimerTask()
{
   public void run()
   {
      //do something and:
      timer2.schedule(tt2, delay2);
   }
};

tt2 = new TimerTask()
{
   public void run()
   {
      //do something and:
      timer1.schedule(tt1, delay1);
   }
};

timer1.schedule(tt1, delay1);

i have two demos, one with jquery and one without. neither use date functions and are about as simple as it gets.

demo with vanilla javascript

function starttimer(duration, display) {
    var timer = duration, minutes, seconds;
    setinterval(function () {
        minutes = parseint(timer / 60, 10);
        seconds = parseint(timer % 60, 10);

        minutes = minutes < 10 ? "0" + minutes : minutes;
        seconds = seconds < 10 ? "0" + seconds : seconds;

        display.textcontent = minutes + ":" + seconds;

        if (--timer < 0) {
            timer = duration;
        }
    }, 1000);
}

window.onload = function () {
    var fiveminutes = 60 * 5,
        display = document.queryselector('#time');
    starttimer(fiveminutes, display);
};
<body>
    <div>registration closes in <span id="time">05:00</span> minutes!</div>
</body>

demo with jquery

function starttimer(duration, display) {
    var timer = duration, minutes, seconds;
    setinterval(function () {
        minutes = parseint(timer / 60, 10);
        seconds = parseint(timer % 60, 10);

        minutes = minutes < 10 ? "0" + minutes : minutes;
        seconds = seconds < 10 ? "0" + seconds : seconds;

        display.text(minutes + ":" + seconds);

        if (--timer < 0) {
            timer = duration;
        }
    }, 1000);
}

jquery(function ($) {
    var fiveminutes = 60 * 5,
        display = $('#time');
    starttimer(fiveminutes, display);
});

however if you want a more accurate timer that is only slightly more complicated:

function starttimer(duration, display) {
    var start = date.now(),
        diff,
        minutes,
        seconds;
    function timer() {
        // get the number of seconds that have elapsed since 
        // starttimer() was called
        diff = duration - (((date.now() - start) / 1000) | 0);

        // does the same job as parseint truncates the float
        minutes = (diff / 60) | 0;
        seconds = (diff % 60) | 0;

        minutes = minutes < 10 ? "0" + minutes : minutes;
        seconds = seconds < 10 ? "0" + seconds : seconds;

        display.textcontent = minutes + ":" + seconds; 

        if (diff <= 0) {
            // add one second so that the count down starts at the full duration
            // example 05:00 not 04:59
            start = date.now() + 1000;
        }
    };
    // we don't want to wait a full second before the timer starts
    timer();
    setinterval(timer, 1000);
}

window.onload = function () {
    var fiveminutes = 60 * 5,
        display = document.queryselector('#time');
    starttimer(fiveminutes, display);
};
<body>
    <div>registration closes in <span id="time"></span> minutes!</div>
</body>

now that we have made a few pretty simple timers we can start to think about re-usability and separating concerns. we can do this by asking "what should a count down timer do?"

  • should a count down timer count down? yes
  • should a count down timer know how to display itself on the dom? no
  • should a count down timer know to restart itself when it reaches 0? no
  • should a count down timer provide a way for a client to access how much time is left? yes

so with these things in mind lets write a better (but still very simple) countdowntimer

function countdowntimer(duration, granularity) {
  this.duration = duration;
  this.granularity = granularity || 1000;
  this.tickftns = [];
  this.running = false;
}

countdowntimer.prototype.start = function() {
  if (this.running) {
    return;
  }
  this.running = true;
  var start = date.now(),
      that = this,
      diff, obj;

  (function timer() {
    diff = that.duration - (((date.now() - start) / 1000) | 0);

    if (diff > 0) {
      settimeout(timer, that.granularity);
    } else {
      diff = 0;
      that.running = false;
    }

    obj = countdowntimer.parse(diff);
    that.tickftns.foreach(function(ftn) {
      ftn.call(this, obj.minutes, obj.seconds);
    }, that);
  }());
};

countdowntimer.prototype.ontick = function(ftn) {
  if (typeof ftn === 'function') {
    this.tickftns.push(ftn);
  }
  return this;
};

countdowntimer.prototype.expired = function() {
  return !this.running;
};

countdowntimer.parse = function(seconds) {
  return {
    'minutes': (seconds / 60) | 0,
    'seconds': (seconds % 60) | 0
  };
};

so why is this implementation better than the others? here are some examples of what you can do with it. note that all but the first example can't be achieved by the starttimer functions.

an example that displays the time in xx:xx format and restarts after reaching 00:00

an example that displays the time in two different formats

an example that has two different timers and only one restarts

an example that starts the count down timer when a button is pressed

this is a bug in javac starting from jdk 9 (which made some changes with regard to string concatenation, which i suspect is part of the problem), as confirmed by the javac team under the bug id jdk-8204322. if you look at the corresponding bytecode for the line:

array[i++%size] += i + " ";

it is:

  21: aload_2
  22: iload_3
  23: iinc          3, 1
  26: iload_1
  27: irem
  28: aload_2
  29: iload_3
  30: iinc          3, 1
  33: iload_1
  34: irem
  35: aaload
  36: iload_3
  37: invokedynamic #5,  0 // makeconcatwithconstants:(ljava/lang/string;i)ljava/lang/string;
  42: aastore

where the last aaload is the actual load from the array. however, the part

  21: aload_2             // load the array reference
  22: iload_3             // load 'i'
  23: iinc          3, 1  // increment 'i' (doesn't affect the loaded value)
  26: iload_1             // load 'size'
  27: irem                // compute the remainder

which roughly corresponds to the expression array[i++%size] (minus the actual load and store), is in there twice. this is incorrect, as the spec says in jls-15.26.2:

a compound assignment expression of the form e1 op= e2 is equivalent to e1 = (t) ((e1) op (e2)), where t is the type of e1, except that e1 is evaluated only once.

so, for the expression array[i++%size] += i + " ";, the part array[i++%size] should only be evaluated once. but it is evaluated twice (once for the load, and once for the store).

so yes, this is a bug.


some updates:

the bug is fixed in jdk 11 and was back-ported to jdk 10 (here and here), but not to jdk 9, since it no longer receives public updates.

aleksey shipilev mentions on the jbs page (and @didierl in the comments here):

workaround: compile with -xdstringconcat=inline

that will revert to using stringbuilder to do the concatenation, and doesn't have the bug.

for just this particular case, i guess this would be a simpler version:

map<integer, list<integer>> map =
        list.stream()
            .collect(collectors.tomap(
                collection::size,
                x -> x.stream().filter(y -> y % 2 == 0).collect(collectors.tolist())
            ));

if there would be merging involved (two collections that would have the same size), i would add a merge function that is pretty trivial:

 map<integer, list<integer>> map =
        list.stream()
            .collect(collectors.tomap(
                collection::size,
                x -> x.stream().filter(y -> y % 2 == 0).collect(collectors.tocollection(arraylist::new)),
                (left, right) -> {
                    left.addall(right);
                    return left;
                }
            ));

otherwise, i agree with michael in this comment, this is not that hard to back-port to java-8.

don't keep creating a new timer in your waitreminderlist() method. you should define the timer as a class variable.

then you just stop/start it as required.


Tags: Java