How to keep updating a date/calendar object? - java

I am making a small alarm clock application to brush up on Java. The purpose of the app is to let the user set the clock time and alarm time, and then the alarm should "go off" when the system time is equal to the alarm time.
The clock class contains a Calendar and Date object.
The clock is referred to from a main method outside the class. In that main method, I have built a simple command line user interface, where the user can set the time of the clock and alarm. By default, the clock is initialized to the current system time.
However, here is where the problem is for both the automatically initialized and the user defined clock objects - they aren't "ticking" or updating.
Clock regularClock = new Clock(); //Defaults clock (using a Date) to the system time
while (userInput != "Quit")
{
switch(userInput)
{
...Other choices here...
case "Set Time": System.out.print("Enter hour: ");
hours = kb.nextInt();
System.out.print("\nEnter minutes: ");
minutes = kb.nextInt();
ACR.regularClock.setTime(hours, minutes);
System.out.println("Clock has been set");
case "Set Alarm": System.out.print("Enter hour: ");
hours = kb.nextInt();
System.out.print("\nEnter minutes: ");
minutes = kb.nextInt();
ACR.alarmClock.setTime(hours, minutes);
ACR.alarmClock.setAlarmOn(true);
System.out.println("Alarm has been set.");
break;
...Other choices here...
userInput = keyboard.next();
}
As you will see, there are no loops or anything to refresh or keep the regularClock ticking. For some reason, when I started I thought Date and Calendar objects just kept running once created - sort of like a stopwatch.
So now I'm wondering what the best way to update them would be, in this while loop. If only the default system time clock was allowed, it would be easy - I could just create a new Date object at the beginning of the while loop each time. However, that would override the user created clock time if they chose that.
Also, if the user weren't to enter any input - and instead just let the app sit there - where he/she would enter input - shouldn't it still be refreshing the times and checking if the regularClock = alarmClock time? How can I do this?
I realize I'm sort of rambling now, so I'll leave it at that. I've been working at this but can't figure out the best solution. If you have any questions, please let me know!
Short summary questions:
How do I keep a the time in a Date or Calendar object ticking, even when it has been modified?
How can I continuously update these objects, while waiting for user input?

There are easier ways, but that's not the question ;)
Basically, you need to establish some kind of "tick" thread that can update/modify the clock in the background...
You can write your own Thread / Runnable to perform these tasks, but they are inherently inaccurate...
Something like...
Thread thread = new Thread(new Ticker());
thread.setDaemon(true); // Otherwise the JVM won't stop when you want it t
thread.start();
//...
public class Ticker implements Runnable {
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException exp) {
}
// Update static reference to the clock...
}
}
}
Beware though
Causes the currently executing thread to sleep (temporarily cease
execution) for the specified number of milliseconds, subject to the
precision and accuracy of system timers and schedulers. The thread
does not lose ownership of any monitors.
Another way would be use the java.util.Timer
Timer timer = new Timer(true);
timer.scheduleAtFixedRate(new Ticker(), 1000, 1000);
//...
public class Ticker extends TimerTask {
public void run() {
// Update static reference to the clock...
}
}
Again, beware...
Subsequent executions take place at approximately regular intervals

Date and Calendar objects do not 'run' - they represent specific points in time.
I believe that what you are looking for is the Timer class.

Related

How to create a single thread cooldown

I'm finding the way to make a Single thread cooldown but get stuck.
In the class who manages the cooldown I created a:
private HashMap<UUID,Integer> players = new HashMap<>();
//UUID = Player UUID
//Integer = Time in cooldown (Seconds)
public void run(){
for(UUID player : players){
//WHAT I NEED TO DO HERE?
if(//Time == 0){
players.remove(player);
}
}
}
Didn't use an IDE hopefully I didn't miss an error that eclipse would have picked up.
But how I can get the integer and save it with a second less?
TimeUnit is used for delaying a process, as it could be used as followed:
TimeUnit.SECONDS.sleep(1);
This will delay the current thread by one second.
I won't suggest using it, because your situation sounds more like a thread is working in the background and you want to wait till it has finished! Therefore use the new feature isAlive, which could be used in a (while) loop.
Edit
If you do want to delay a thread from another thread over the instance, then I'd suggest using the sleep method.
Example:
myThread.sleep(1000);
This will delay myThread by one second.
Edit #2
To change a value for a certain key of a HashMap, use the put and get method.
Example:
// Get the time of a player and subtract it by one
Integer value = players.get(player) - 1;
// Update the value
players.put(player, value);
// If the time runs out, than delete the player
if (value == 0){
players.remove(player);
}

Wait for system time to continue application

I've written a class to continue a started JAVA application if the current second is a multiple of 5 (i.e. Calender.SECOND % 5 == 0)
The class code is presented below, what I'm curious about is, am I doing this the right way? It doesn't seem like an elegant solution, blocking the execution like this and getting the instance over and over.
public class Synchronizer{
private static Calendar c;
public static void timeInSync(){
do{
c = Calendar.getInstance();
}
while(c.get(Calendar.SECOND) % 5 != 0);
}
}
Synchronizer.timeInSync() is called in another class's constructor and an instance of that class is created at the start of the main method. Then the application runs forever with a TimerTask that's called every 5 seconds.
Is there a cleaner solution for synchronizing the time?
Update:
I think I did not clearly stated but what I'm looking for here is to synchronization with the system time without doing busy waiting.
So I need to be able to get
12:19:00
12:19:05
12:19:10
...
What you have now is called busy waiting (also sometimes referred as polling), and yes its inefficient in terms of processor usage and also in terms of energy usage. You code executes whenever the OS allows it, and in doing so it prevents the use of a CPU for other work, or when there is no other work it prevents the CPU from taking a nap, wasting energy (heating the CPU, draining the battery...).
What you should do is put your thread to sleep until the time where you want to do something arrives. This allows the CPU to perform other tasks or go to sleep.
There is a method on java.lang.Thread to do just that: Thread.sleep(long milliseconds) (it also has a cousin taking an additional nanos parameter, but the nanos may be ignored by the VM, and that kind of precision is rarely needed).
So first you determine when you need to do some work. Then you sleep until then. A naive implementation could look like that:
public static void waitUntil(long timestamp) {
long millis = timestamp - System.currentTimeMillis();
// return immediately if time is already in the past
if (millis <= 0)
return;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
This works fine if you don't have too strict requirements on precisely hitting the time, you can expect it to return reasonably close to the specified time (a few ten ms away probably) if the time isn't too far in the future (a few secs tops). You have however no guarantees that occasionally when the OS is really busy that it possily returns much later.
A slightly more accurate method is to determine the reuired sleep time, sleep for half the time, evaluate required sleep again, sleep again half the time and so on until the required sleep time becomes very small, then busy wait the remaining few milliseconds.
However System.currentTimeMillis() does not guarantee the actual resolution of time; it may change once every millisecond, but it might as well only change every ten ms by 10 (this depends on the platform). Same goes for System.nanoTime().
Waiting for an exact point in time is not possible in high level programming languages in a multi-tasking environment (practically everywhere nowadays). If you have strict requirements, you need to turn to the operating system specifics to create an interrupt at the specified time and handle the event in the interrupt (that means assembler or at least C for the interrupt handler). You won't need that in most normal applications, a few ms +/- usually don't matter in a game/application.
As #ChrisK suggests, you could simplify by just making a direct call to System.currentTimeMillis().
For example:
long time = 0;
do
{
time = System.currentTimeMillis();
} while (time % 5000 != 0);
Note that you need to change the comparison value to 5000 because the representation of the time is in milliseconds.
Also, there are possible pitfalls to doing any comparison so directly like this, as the looping call depends on processor availability and whatnot, so there is a chance that an implementation such as this could make one call that returns:
`1411482384999`
And then the next call in the loop return
`1411482385001`
Meaning that your condition has been skipped by virtue of hardware availability.
If you want to use a built in scheduler, I suggest looking at the answer to a similar question here java: run a function after a specific number of seconds
You should use
System.nanoTime()
instead of
System.currentTimeMillis()
because it returns the measured elapsed time instead of the system time, so nanoTime is not influenced by system time changes.
public class Synchronizer
{
public static void timeInSync()
{
long lastNanoTime = System.nanoTime();
long nowTime = System.nanoTime();
while(nowTime/1000000 - lastNanoTime /1000000 < 5000 )
{
nowTime = System.nanoTime();
}
}
}
The first main point is that you must never use busy-waiting. In java you can avoid busy-waiting by using either Object.wait(timeout) or Thread.sleep(timeout). The later is more suitable for your case, because your case doesn't require losing monitor lock.
Next, you can use two approaches to wait until your time condition is satisfied. You can either precalculate your whole wait time or wait for small time intervals in loop, checking the condition.
I will illustrate both approaches here:
private static long nextWakeTime(long time) {
if (time / 1000 % 5 == 0) { // current time is multiple of five seconds
return time;
}
return (time / 1000 / 5 + 1) * 5000;
}
private static void waitUsingCalculatedTime() {
long currentTime = System.currentTimeMillis();
long wakeTime = nextWakeTime(currentTime);
while (currentTime < wakeTime) {
try {
System.out.printf("Current time: %d%n", currentTime);
System.out.printf("Wake time: %d%n", wakeTime);
System.out.printf("Waiting: %d ms%n", wakeTime - currentTime);
Thread.sleep(wakeTime - currentTime);
} catch (InterruptedException e) {
// ignore
}
currentTime = System.currentTimeMillis();
}
}
private static void waitUsingSmallTime() {
while (System.currentTimeMillis() / 1000 % 5 != 0) {
try {
System.out.printf("Current time: %d%n", System.currentTimeMillis());
Thread.sleep(100);
} catch (InterruptedException e) {
// ignore
}
}
}
As you can see, waiting for the precalculated time is more complex, but it is more precise and more efficient (since in general case it will be done in single iteration). Waiting iteratively for small time interval is simpler, but less efficient and precise (precision is dependent on the selected size of the time interval).
Also please note how I calculate if the time condition is satisfied:
(time / 1000 % 5 == 0)
In first step you need to calculate seconds and only then check if the are multiple of five. Checking by time % 5000 == 0 as suggested in other answer is wrong, as it is true only for the first millisecond of each fifth second.

Constant thread loop time Java

I want to have a thread that loops at a constant amount of times per second for example a render loop that aims for a constant framerate. The loop would obviously slow if the time it takes exceeds the time allowed.
Thanks.
How about
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleAtFixedRate(0, delay, TimeUnit.MILLI_SECONDS, new Runnable() {
public void run() {
// do something
}
});
or
long delay = ....
long next = System.currentTimeMillis();
while(running) {
// do something
next += delay;
long sleep = next - System.currentTimeMillis();
if (sleep > 0)
Thread.sleep(sleep);
}
There are two basic techniques you need two consider:
seperate updateing your model or state of the world from rendering it.
If you have done that, you can sleep/wait the appropriate amount of time before rendering stuff or skip the rendering for some frames if you fall behind your planed schedule.
I can recommend two good tututorials on how to implement something like a game loop in java/android.
First one about the basics is http://obviam.net/index.php/a-very-basic-the-game-loop-for-android/
and the second one has a focus on constant Frames per Second: http://obviam.net/index.php/the-android-game-loop/. I think the lessons apply to regualar java as well.

Performing a task every x time

I'm trying to perform a task every 5 minute.
The task need to start from: xx:00, xx:05, xx:10, xx:15 and so on so if the time is xx:37 the task will start in xx:40.
I'm used the following code to do that:
Date d1 = new Date();
d1.setMinutes(d1.getMinutes() + 5 - d1.getMinutes()%5);
d1.setSeconds(0);
this.timer.schedule(new Send(), d1, TEN_MINUTES/2);
Send looks like that:
class Send extends TimerTask
{
public void run()
{
if(SomeCondition)
{
Timestamp ts1 = new Timestamp(new java.util.Date().getTime());
SendToDB(ts1);
}
}
}
So the result should be records that if you % the minutes the result would be 0.
But the records time I have is:
*05:35:00
*07:44:40
*07:54:40
*09:05:31
*09:50:00
As you can see the first task start perfectly but then something went wrong.
My guess is that the task calculateds the 5 minute jump after the previous task is finished so the task run time effects, but it's just a guess.
The time a task takes to execute will delay the schedule. From the docs for schedule:
If an execution is delayed for any reason (such as garbage collection or other background activity), subsequent executions will be delayed as well.
You will be better off using scheduleAtFixedRate.
Alternatively, you might try using a simple Thread with a loop to repeatedly perform the task. The last step in the loop can be to sleep the necessary time until you want to start the task again. Assuming that no one iteration of the loop takes five minutes, this will eliminate cumulative delays.
public void run() {
long start = System.currentTimeMillis();
while (shouldRun()) {
doTask();
long next = start + FIVE_MINUTES;
try {
Thread.sleep(next - System.currentTimeMillis());
start = next;
} catch (InterruptedException e) {
. . .
}
}
}
This will start each iteration at the next five-minute interval and will not accumulate delays due to the running time of doTask() or any system delays. I haven't looked at the sources, but I suspect that this is close to what's in Timer.scheduleAtFixedRate.
Why dont you use a Task scheduler or simply a sleep command in a loop which lets the thread sleep for 5 minutes then continue.
An alternative would be to use a Timer class
I would probably make use of ScheduleExecutorService.scheduleAtFixedRate which is a more modern approach than using a Timer and would allow for having multiple worker threads in case there are many tasks being scheduled.

(Java) Ticker that adds to counter variable

Im trying to get a timer to work in my current java project that adds 1 to an integer variable every n microseconds (e.g. 500 for 1/2 a second), within an infinite loop, so that it is always running while the program runs.
Heres the code i have currently:
public class Ticker
{
public int time = 0;
long t0, t1;
public void tick(int[] args)
{
for (int i = 2; i < 1; i++)
{
t0 = System.currentTimeMillis();
do
{
t1 = System.currentTimeMillis();
}
while (t1 - t0 < 500);
time = time + 1;
}
}
}
Everyone was so helpful with my last question, hopefully this one is just as easy
Here is an comparable ScheduledExecutorService example which will update the time variable with a 500 millisecond interval:
ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
exec.scheduleAtFixedRate(new Runnable(){
private int time = 0;
#Override
public void run(){
time++;
System.out.println("Time: " + time);
}
}, 0, 500, TimeUnit.MILLISECONDS);
This approach is preferred over using Timer.
I think you want
Thread.sleep(500);
At the moment you're consuming CPU cycles waiting for 500ms (you mention microseconds but I believe you want milliseconds). The above puts your current thread to sleep for 500ms and your process won't consume any CPU (or minimal at least - garbage collection will still be running). If you watch the CPU when you run your version you should see the difference.
See here for more info.
If you need to do it in a different thread, take a look on Timer:
int delay = 500; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
time++
}
};
new Timer(delay, taskPerformer).start();
Note that the code above cannot utilize a local variable (they must be declared as final to access them in an anonymous class). It can be a member however.
What you have is rather inefficient, since it wastes CPU cycles waiting for the next wakeup time. If I were you, I'd rewrite the function using Thread.sleep().
As to why your current code doesn't work, your for loop conditions are off, so the loop is never entered.
To have the timer code run concurrently with whatever other logic you have in your program, you'll need to look into threading.
It sounds like you might want to look into multithreading. If you search SO for this, you will find several good question/answer threads. There are also tutorials elsewhere on the web...
Have a look at Timer or better ScheduledExecutorService. They enable you to execute some action periodically and handle the computations surrounding that.

Categories