Update current time date without exploding in memory - java

I have written the following Java code:
Calendar now = Calendar.getInstance();
now.setTime(new Date());
Date currentDate = null;
while (now.compareTo(stop) < 0 ) {
currentDate = new Date();
now.setTime(currentDate);
}
that is meant to track down the time passing while other components (in particular: a Twitter Streaming listener) perform other actions. So, this is not meant to be a simple sleep, since other components are running in the meanwhile: this loop is just meant to keep the machine occupied for a while, until the date indicated by stop arrives.
However, by doing this the memory size keeps increasing a lot. I profiled the thing and I saw that this generates a huge amount of Date objects in memory.
Is there a smarter way of doing this?
Thank you in advance.

The minimum change is to use setTimeInMillis using System.currentTimeMillis rather than setTime:
while (now.compareTo(stop) < 0 ) { // Ugh, busy wait, see below
now.setTimeInMillis(System.currentTimeMillis());
}
...or actually, just use milliseconds in the first place:
long stopAt = stop.getTimeMillis();
while (System.currentTimeMillis() < stopAt) { // Ugh, busy wait, see below
}
However, surely with broader context there's a way to avoid busy-waiting at all. Busy-waits are almost never appropriate.
So, this is not meant to be a simple sleep, since other components are running in the meanwhile: this loop is just meant to keep the machine occupied for a while, until the date indicated by stop arrives.
Presumably those components are running on other threads, as your while loop is a busy-wait.
That being the case, this thread should sleep — either for a period of time, or until it's woken up by something else.
For instance, you haven't said what stop is, but as you're using it with compareTo presumably it's a Calendar. So it should be possible to get the difference (in milliseconds, via getTimeInMillis) between stop and now, and sleep rather than busy-waiting:
Calendar now = Calendar.getInstance(); // Initializes to "now", no need to do that yourself
long delay = stop.getTimeInMillis() - now.getTimeInMillis();
if (delay > 0) {
Thread.sleep(delay);
}

Related

How to use System.nanoTime() for sequencing events with more precision

I want to attach a timestamp whenever an event happens in my application. Let's assume that a client creates a Event object and I want to attach a creation timestamp to the Event object. I can do this using the System.currentTimeMillis() within the constructor. This works fine if the Event objects are created no faster than once every millisecond. In this case each Event object gets a different value from System.currentTimeMillis() and hence the Event objects are sequenced.
However if the Event objects need to be created a rate that is faster than one object per millisecond, then my logic breaks. Depending on the rate of object creation 2 or more Event objects end up having the same creation timestamp (since System.currentTimeMillis returned the same value when called in quick succession)
Now how do I sequence the Event objects in this case? I am aware of the System.nanoTime() but that's not related to the epoch.
I am open to storing the creation timestamp within the Event class split into 2 instance variables - creationTimeInMS (long) and creationTimeInNS (long)
I do not want to java.sql.Timestamp which does support nano second precision
Is there anyway I could leverage the System.nanoTime to provide sequencing of the event objects?
Note - It is guaranteed that the event will not get created faster than 1 per nanosecond. Hence nanosecond precision will suffice
The code that I have using is as below
class Event {
private long timestamp
public Event() {
...
timestamp = System.currentTimeMillis()
}
So if the Event constructor is called by multiple threads at a rate faster than 1 per millisecond, then two (or more) Event objects get the same timestamp.
The System.nanoTime() is supposed to return unique number if called no faster than once every nano second. However I am not sure how I could use this number in conjunction with the timestamp. Do I add this to the timestamp to generate a nano second precision time?
It is hard to achieve that with relying on the wall clock, times are gonna collide and nano second resolution is hard to achieve in practice, a quick solution is to add a wrapper around the time that remembers its last value. This wont work in a distributed environment of course.
static class MonotonicClock{
private long last;
public MonotonicClock(){
last = System.currentTimeMillis();
}
public synchronized long getNext(){
long current = System.currentTimeMillis();
if(last < current){ // last seen is less than "now"
last = current;
}else{
last++; //collision, overclock the time
}
return last;
}
}
In a distributed system, things are more complicated. You might need to look at Lamport timestamps and Vector Clocks for that.

Java "scheduleAtFixedRate" alternative solution?

I have a Java application that is used to communicate with an embedded device over a UART connection (RS422). The host queries the microcontroller for data in 5 millisecond intervals. Up until recently I've been using ScheduledExecutorService scheduleAtFixedRate to call my communication protocol method, but it turns out scheduleAtFixedRate is very unreliable for this desired level of precision (as many other posts reveal). Among the data returned from the microcontroller is a timestamp (in microseconds), allowing me to verify the interval between received data packets independently of the JVM. Needless to say, the interval when using scheduleAtFixedRate varied wildly - up to 30 milliseconds between packets. Additionally, the scheduler will then try to overcompensate for the missed cycles by calling the Runnable several times within one millisecond (again, no surprise to anyone here).
After some searching, there seemed to be a consensus that the JVM simply could not be trusted to ensure any kind of precise scheduling. However, I decided to do some experimenting on my own and came up with this:
Runnable commTask = () -> {
// volatile boolean controlled from the GUI
while(deviceConnection) {
// retrieve start time
startTime = System.nanoTime();
// time since commProtocol was last called
timeDiff = startTime - previousTime;
// if at least 5 milliseconds has passed
if(timeDiff >= 5000000) {
// handle communication
commProtocol();
// store the start time for comparison
previousTime = startTime;
}
}
};
// commTask is started as follows
service = Executors.newSingleThreadScheduledExecutor();
service.schedule(commTask, 0, TimeUnit.MILLISECONDS);
The result of this was fantastic. Adjacent timestamps never varied by more than 0.1 milliseconds from the expected 5 millisecond interval. Despite this, something about this technique doesn't seem right, but I haven't been able to come up with anything else that works. My question is basically whether or not this approach is OK, and if not, what should I do instead?
(I am running Windows 10 with JDK 8_74)
Based on the information I've received in the comments, I've decided to use leave my code essentially intact (with the exception of Thread.yield() which I've added to the while loop). I have used this for a few months now and am very satisfied with the performance from this approach. See the final code below.
Runnable commTask = () -> {
// volatile boolean controlled from the GUI
while(deviceConnection) {
// retrieve start time
startTime = System.nanoTime();
// time since commProtocol was last called
timeDiff = startTime - previousTime;
// if at least 5 milliseconds has passed
if(timeDiff >= 5000000) {
// handle communication
commProtocol();
// store the start time for comparison
previousTime = startTime;
}
Thread.yield();
}
};
// commTask is started as follows
service = Executors.newSingleThreadScheduledExecutor();
service.execute(commTask);

How do I use Android's Handler.PostDelayed to make an event happen at a specified time?

I want to have my application execute code at a point in the future.
I want to do:
Date now = new Date();
for (Date beep : scheduledBeeps) {
if (beep.after(now))
{
Logger.i("adding beep");
m_beepTimer.postAtTime(beepNow, beep.getTime());
}
}
In the log I can see 4 beeps added, however they never fire. I'm assuming it has something to do with uptimeMillis, but I'm not sure what to do.
You will have to get the difference between now and beep.gettime() and pass it to postattime function. Since uptime is used as base, it may not be accurate if the phone goes to deep sleep.
beep.gettime - now + SystemCLock.uptimeMillis()
should be passed to postattime function
You are currently passing a very large number equivalent to current milliseconds from jan 1 1970.
You could use the Calendar class to set a certain point in time.
Calendar beepTime = Calendar.getInstance();
beepTime.set(Calendar.DAY_OF_MONTH, 2);
beepTIme.set(Calendar.HOUR_OF_DAY, 01);
beepTime.set(Calendar.MINUTE, 55);
beepTime.set(Calendar.SECOND, 00);
getInstance will set it to the current time, and you can change any variable you like, such as the ones above. For example this would create a time at 1:55 on the 2nd of the current month. You would then set this to be the time to go off with
beepTime.getTimeInMillis()
just pop that into your postAtTime method
Edit: Also I don't know enough about your problem to say for sure, but it may be better to use AlarmManager. I know that that still works even if the program is not running, whereas I don't think PostDelayed does. Feel free to correct me if I'm wrong!

Traceview shows some methods arent being called for 200ms or more

Traceview shows that updatePhysics() is being called every 10ms or so and it takes about 8ms to run. The methods that I call inside updatePhysics are only running once every 5 or 6 times updatePhysics() runs, however. Is this simply a bug of Traceview, or what is going on? My game is stuttering a fair amount, so I am trying to figure out what is causing it.
Traceview is generally showing that a lot of my methods go several hundred milliseconds without being called once, even though there appears to be no reason they shouldnt be called. Ideas?
Run Method:
while (mRun)
{
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Canvas c = null;
try
{
c = mSurfaceHolder.lockCanvas(null);//null
{
time2 = System.nanoTime()/100000; // Get current time
float delta = (time2 - time1)/1000f;
if (mMode == STATE_RUNNING) updatePhysics(delta);
else updateMenus();
doDraw(c);
time1 = time2;
}
} finally
{
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null)
{
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
Update Physics:
private void updatePhysics(float delta)
{
updateScore(delta);
updateDifficulty();
}
EDIT: As you can see here, updateDifficulty is often not called for several hundred ms EVEN THOUGH updatePhysics is being called regularly... It makes no sense. Screenshot of traceview
Most likely somewhere in your thread you're calling thread.Sleep(0) or thread.Yield() or something like that. This will cause a thread to yield to other threads that are being scheduled. And it will often take 10ms or more before the thread gets scheduled back in. I think traceview doesn't understand this fully and counts the time the thread is in suspended state as being active.
Most games use a constant game loop, a real while(true) that never yields to anything.
Some other comments:
I would try the code without the try-catch block, this will slow things down considerabely. Als remove the threadpriority line, this is an OS call and could be slow, and would not add any speed in case of a bug. (It should be fine on normal priority)
Also are you sure this is correct:
time2 = System.nanoTime()/100000; // Get current time
float delta = (time2 - time1)/1000f;
I don't see why you require to devide the delta and the current time. Either convert the time from nanotime to seconds (or whatever you require), and then have a delta in seconds. Or keep time in nanoseconds and convert the delta to seconds. Now you first convert to seconds and then to 1/1000th of a second.

System.nanotime running slow?

One of my friends showed me something he had done, and I was at a serious loss to explain how this could have happened: he was using a System.nanotime to time something, and it gave the user an update every second to tell how much time had elapsed (it Thread.sleep(1000) for that part), and it took seemingly forever (something that was waiting for 10 seconds took roughly 3 minutes to finish). We tried using millitime in order to see how much time had elapsed: it printed how much nanotime had elapsed every second, and we saw that for every second, the nanotime was moving by roughly 40-50 milliseconds every second.
I checked for bugs relating to System.nanotime and Java, but it seemed the only things I could find involved the nanotime suddenly greatly increasing and then stopping. I also browsed this blog entry based on something I read in a different question, but that didn't have anything that may cause it.
Obviously this could be worked around for this situation by just using the millitime instead; there are lots of workarounds to this, but what I'm curious about is if there's anything other than a hardware issue with the system clock or at least whatever the most accurate clock the CPU has (since that's what System.nanotime seems to use) that could cause it to run consistently slow like this?
long initialNano = System.nanoTime();
long initialMili = System.currentTimeMillis();
//Obviously the code isn't actually doing a while(true),
//but it illustrates the point
while(true) {
Thread.sleep(1000);
long currentNano = System.nanoTime();
long currentMili = System.currentTimeMillis();
double secondsNano = ((double) (currentNano - initialNano))/1000000000D;
double secondsMili = ((double) (currentMili - initialMili))/1000D;
System.out.println(secondsNano);
System.out.println(secondsMili);
}
secondsNano will print something along the lines of 0.04, whereas secondsMili will print something very close to 1.
It looks like a bug along this line has been reported at Sun's bug database, but they closed it as a duplicate, but their link doesn't go to an existing bug. It seems to be very system-specific, so I'm getting more and more sure this is a hardware issue.
... he was using a System.nanotime to cause the program to wait before doing something, and ...
Can you show us some code that demonstrates exactly what he was doing? Was it some strange kind of busy loop, like this:
long t = System.nanoTime() + 1000000000L;
while (System.nanoTime() < t) { /* do nothing */ }
If yes, then that's not the right way to make your program pause for a while. Use Thread.sleep(...) instead to make the program wait for a specified number of milliseconds.
You do realise that the loop you are using doesn't take exactly 1 second to run? Firstly Thread.sleep() isn't guaranteed to be accurate, and the rest of the code in the loop does take some time to execute (Both nanoTime() and currentTimeMillis() actually can be quite slow depending on the underlying implementation). Secondly, System.currentTimeMillis() is not guaranteed to be accurate either (it only updates every 50ms on some operating system and hardware combinations). You also mention it being inaccurate to 40-50ms above and then go on to say 0.004s which is actually only 4ms.
I would recommend you change your System.out.println() to be:
System.out.println(secondsNano - secondsMili);
This way, you'll be able to see how much the two clocks differ on a second-by-second basis. I left it running for about 12 hours on my laptop and it was out by 1.46 seconds (fast, not slow). This shows that there is some drift in the two clocks.
I would think that the currentTimeMillis() method provides a more accurate time over a large period of time, yet nanoTime() has a greater resolution and is good for timing code or providing sub-millisecond timing over short time periods.
I've experienced the same problem. Except in my case, it is more pronounced.
With this simple program:
public class test {
public static void main(String[] args) {
while (true) {
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
}
OStream.out("\t" + System.currentTimeMillis() + "\t" + nanoTimeMillis());
}
}
static long nanoTimeMillis() {
return Math.round(System.nanoTime() / 1000000.0);
}
}
I get the following results:
13:05:16:380 main: 1288199116375 61530042
13:05:16:764 main: 1288199117375 61530438
13:05:17:134 main: 1288199118375 61530808
13:05:17:510 main: 1288199119375 61531183
13:05:17:886 main: 1288199120375 61531559
The nanoTime is showing only ~400ms elapsed for each second.

Categories

Resources