Execute in future - time doubles somehow - java

I am very sorry to ask this question but something is going wrong with my code. Currently I am playing around with Command Patterns and I want a command class to execute code in the future - lets say 2 seconds in the future. The problem somehow is that the command gets executed in 5 seconds, not in 2??? Each call decreases a time variable until the variable is <= 0:
// 2 seconds in nanoseconds
private long timeLeft = 2000000000;
public boolean execute(final long delta) {
this.timeLeft -= delta;
if (this.timeLeft <= 0) {
// execute
this.timeLeft = 2000000000l;
return true
}
return false;
}
With lastExecution = System.nanoTime(); and then for each command delta = System.nanoTime() - lastExecution;
Full src on github: https://github.com/Sheldor5/JavaGPP

Instead of decrementing a countdown timer value by inaccurate deltas, calculate the target time and check for it, and use milli-time, not nano-time, to prevent sign issues.
long targetMillis = System.currentTimeMillis() + 2000; // 2 sec
while (System.currentTimeMillis() < targetMillis) {
// do something while we wait
}
// 2 secs elapsed, may be a bit more

Related

How to run a For Loop for 60 seconds maximum irrespective of the size of the loop and complete all the iterations

for(i=1;i<list.size();i++){
//do something
//For Eg: move marker to a new position on the map
}
I want the above loop to complete all the iterations irrespective of the size of the list and also want the entire task to run for 1 minute. (60 seconds)
I don't really know if this is what you want but I hope this helps.
import java.util.concurrent.TimeUnit;
for(i=1;i<list.size();i++){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Execute thing you want to be executed every second
}
As explanation: you iterate through the for loop and the thread waits for one second before executing the code after the TimeUnit.SECONDS.sleep(1);.
If the list's size is 60 it would therefore take a minute for the loop to end.
Edit: It has occurred to me that it might be smarter to do a try-catch around the sleep function.
You can, for example, use System.nanoTime() to measure the duration of your loop, and then use TimeUnit.NANOSECONDS.sleep(...) to make it wait for the rest of time like this:
long start = System.nanoTime();
long desiredDuration = 60 * 1000 * 1000;
// your loop goes here
long duration = System.nanoTime() - start;
if (duration < desiredDuration)
TimeUnit.NANOSECONDS.sleep(desiredDuration - duration);
The best possible solution is to compute the desired time first and then run the loop to that extent.
long finish=System.currentTimeMillis() + 60000;
while(System.currentTimeMillis() != finish)
{
//statements;
//statements;
}
If you are trying to equip the CPU and keep it idle for this time the process is known as busy waiting but is not considered convenient in many cases so i recommend to use Thread.sleep(duration) for this purpose.
Would like to receive further queries from your side.
To spread N amount of invocations uniformly across a minute, you'll have to set the delay in between the invocations to the value 60/(N-1). The -1 is optional but causes the first and last invocations to be exactly 60 seconds apart. (just like how a ladder with N rungs has N-1 spaces)
Of course, using sleep() with the number calculated above is not only subject to round-off errors, but also drift, because you do stuff between the delays, and that stuff also takes time.
A more accurate solution is to subtract the time at which each invocation should occur (defined by startTime + 60*i/(N-1)) from the current time. Reorder and reformulate those formulas and you can subtract the 'time that should have elapsed for the next invocation' from the already elapsed time.
Of course 'elapsed time' should be calculated using System.nanoTime() and not System.currentTimeMillis() as the latter can jump when the clock changes or the computer resumes from stand-by.
For this example I changed 60 seconds to 6 seconds so you can more easily see what's going on when you run it.
public static void main(String... args) throws Exception {
int duration = 6; // seconds
List<Double> list = IntStream.range(0, 10).mapToDouble(i->ThreadLocalRandom.current().nextDouble()).boxed().collect(Collectors.toList());
long startTime = System.nanoTime();
long elapsed = 0;
for (int i = 0; i < list.size(); i++) { // Bug fixed: start at 0, not at 1.
if (i > 0) {
long nextInvocation = TimeUnit.NANOSECONDS.convert(duration, TimeUnit.SECONDS) * i / (list.size() - 1);
long sleepAmount = nextInvocation - elapsed;
TimeUnit.NANOSECONDS.sleep(sleepAmount);
}
elapsed = System.nanoTime() - startTime;
doSomething(elapsed, list.get(i));
}
}
private static void doSomething(long elapsedNanos, Double d) {
System.out.println(elapsedNanos / 1.0e9f + "\t" + d);
}
Of course when the task you preform per list element takes longer than 60/(N-1) seconds, you get contention and the 'elapsed time' deadlines are always exceeded. With this algorithm the total time just taking longer than a mnute. However if some earlier invocations exceed the deadline, and later invocations take much less time than 60/(N-1), this algorithm will show 'catch-up' behavior. This can be partially solved by sleeping at least a minimum amount even when sleepAmount is less.
Check out this.
long start = System.currentTimeMillis();
long end = start + 60*1000; // 60 seconds * 1000 ms/sec
int i = 0;
while (System.currentTimeMillis() < end)
{
// do something, iterate your list
i++;
if (i == list.size()) { // check size of the list if iteration is completed
// if time has not yet expired, sleep for the rest of the time
Thread.sleep(end - System.currentTimeMillis());
}
}
Do not forget checking size of the list.

Possible to make #currentTimeMillis a constant? when a value is added to it?

So I'm trying to make the System.currentTimeMillis(); a constant. It's difficult to explain this. What the code is supposed to do is add a value to the System.currentTimeMillis(); which it does and wait till the code returns true and then execute an action. So basically, I'm trying to make a "temp-ban" system. Because System.currentTimeMillis isn't a constant value, of course, this is going to return false. I'm wondering what would I exactly do to make this code become true
long timeleft = StaticMaps.muteMap.get(uuid).getTime() * 1000; //seconds to miliseconds
if (System.currentTimeMillis() >= timeleft + System.currentTimeMillis()) {
plugin.mutemanager.destructPlayerMute(uuid, "Expired", "Removed by Console, Expired!");
} else {
KTools.notify("debug");
e.setCancelled(true);
}
Solution I used
Store the value as a "Long" inside a map with the System.currentTimeMillis();
So what you would do is.
Map<UUID, Long> temp = new HashMap<>();
Long time = 3 * 1000; //3 * 1000 = 3 Seconds
temp.put(Identifier, System.currentTimeMillis() + timetoadd)
timetoadd needs to be a long.
Then check if System.currentTimeMillis() is >= the value in the hashmap.
long HOUR = 3600000;
long DAY = 86400000;
long dayformula = Long.parseLong(parts[0]) * DAY;
long hourformula = Long.parseLong(parts[1]) * HOUR;
long totalmiliseconds = dayformula + hourformula;
You don't want to make that into a constant. You want to store off its value for a given moment in time and use that to check against the current system time.
That's easily accomplished thus:
long timeleft = StaticMaps.muteMap.get(uuid).getTime() * 1000; //seconds to miliseconds
long lastCheckedTime = System.currentTimeMillis();
if (System.currentTimeMillis() >= timeleft + lastCheckedTime) {
plugin.mutemanager.destructPlayerMute(uuid, "Expired", "Removed by Console, Expired!");
} else {
KTools.notify("debug");
e.setCancelled(true);
}
...although to be fair, that statement is almost guaranteed to be false unless timeLeft is on the order of microseconds.
You can't make System.currentTimeMillis(); a constant (var/value) because that's not a var/value, but rather a function that returns one.
What you want to do is save timestamps of the current time (using that), plus ban/mute time, into a map, and then either schedule the lift of the ban/unmute, or manage it yourself by periodically checking System.currentTimeMillis(); and if it's past (above) any expected ban-lift/unmute time (the ones you saved), applying the necessary actions (lifting ban or unmuting).
I'm currently on my phone, and I can't give an example of the schedule method out of my (not very reliable) memory...
But, if it's the managed one, I can try:
//How to "schedule" the lift...
public /*static ?*/ void mutePlayer(??? uuid, long muteTime){
StaticMaps.muteMap.put(uuid, System.currentTimeMillis()+muteTime); //I'm assuming how the syntax is...Adapt as needed.
}
//Somewhere else, inside a loop that runs periodically...
for(Entry<uuid, long> scheduled : Staticamaps.muteMap.entrySet()){
if (System.currentTimeMillis() >= scheduled.value() /*lift timestamp*/)) {
plugin.mutemanager.destructPlayerMute(scheduled.key() /*uuid*/, "Expired", "Mute has expired!");
} else {
KTools.notify("debug");
e.setCancelled(true);
}
}
Note that, since I can't know the syntax or the functions available to muteMap, some of the ones I used should be considered pseudo-code.

Exact timing in Java game loop

I'm developing a network based game, and I'm now focusing on the server side simulation. Of course I need a game loop, and I opted for a fixed timestep loop so that it will be far easier to reproduce on the client(s) than a variable timestep one. I also decided to run my game at 60 Hz. This is the game logic speed, not rendering speed. Rendering will be handled with a variable timestep loop in the clients to have the best possible rendering.
The server is written in Java.
I already made an example game loop using code from http://www.java-gaming.org/index.php?topic=24220.0 and modifying the loop with my code. Here is the loop:
private void gameLoop()
{
final double GAME_HERTZ = 60.0;
final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();
int lastSecondTime = (int) (lastUpdateTime / 1000000000);
long extraSleepTime = 0;
while (running)
{
int updateCount = 0;
if (!paused)
{
long loopStartTime = System.nanoTime();
updateGame();
updateCount++;
long timeAfterUpdate = System.nanoTime();
lastUpdateTime = timeAfterUpdate;
//Render. To do so, we need to calculate interpolation for a smooth render.
float interpolation = Math.min(1.0f, (float) ((loopStartTime - lastUpdateTime) / TIME_BETWEEN_UPDATES) );
drawGame(interpolation);
lastRenderTime = loopStartTime;
//Update the frames we got.
int thisSecond = (int) (lastUpdateTime / 1000000000);
if (thisSecond > lastSecondTime)
{
long nanoTime = System.nanoTime();
System.out.println("NEW SECOND " + thisSecond + " " + frameCount + ": " + (nanoTime - lastNanoTime));
lastNanoTime = nanoTime;
fps = frameCount;
frameCount = 0;
lastSecondTime = thisSecond;
}
long loopExecutionTime = timeAfterUpdate - loopStartTime;
long sleepTime = (long)TIME_BETWEEN_UPDATES - loopExecutionTime - extraSleepTime;
// Only sleep for positive intervals
if(sleepTime >= 0)
{
try
{
Thread.sleep(sleepTime / 1000000);
}
catch(InterruptedException e) {}
}
else
{
System.out.println("WARN: sleepTime < 0");
}
// Counts the extra time that elapsed
extraSleepTime = System.nanoTime() - timeAfterUpdate - sleepTime;
}
}
The problem is that, when running, the FPS aren't stable at 60Hz, but sometimes go lower. For example I sometimes get 58-59Hz, going as low as 57Hz.
This variability wouldn't be a problem if the game was run locally, but as our game is networked, I need to keep the exact time so that I can reproduce the logic calculations on both client and server.
Is there any error in this code, or anything that could be improved to make it more stable? Our goal is 60Hz being kept exactly all the time.
EDIT: A first solution that came up in my mind is running the loop a bit faster than it needs to, for example at 70Hz, and checking the frame count to limit the updates to 60 per seconds. This way the simulation would be run in bursts and would need buffering, (up to 60 frames at a time), but should be able to never be slower than needed.
Thanks in advance.
If you want to achieve 60 frames per second, you'd be better off using a scheduled executor as Thread.sleep() may not be as precise as you'd like it to be. Consider the following sample for your server code: (Please note it contains Java 8 code)
public void gameLoop() {
// game logic here
}
Executors.newSingleThreadScheduledExecutor()
.scheduleAtFixedRate(this::gameLoop, 0, 16, TimeUnit.MILLISECONDS)
It will run your gameLoop() every 16 milliseconds which is essentially what you want. This should give you much more precise results. You can also replace 16 and TimeUnit.MILLISECONDS with their nanoseconds counterpart, even though it shouldn't make any noticeable difference

Interrupt Loop after some Time in Java

I am looking for a way to interrupt a loop in Java without multithreading.
public class Foo{
public Foo(){
}
public void bar(long timeLimit) {
long endTime = System.currentTimeMillis() + (timeLimit * 1000);
while (System.currentTimeMillis() < endTime) {
// Some really long and complicated computation
}
}
}
At the moment I realized that which various (System.currentTimeMillis() < timeLimit) calls to check during the computation if there is time left but I guess that eats up some time and I am also facing the problem that if a loop starts in time, the computation might not be done in time.
Amending the timeLimit (let's say only using 40 % of the time) accordingly also does not work, because I cannot predict how long some computations take.
Which options are there?

Program works great with CountDownTimer until there are 3 seconds left, then it calls twice

I am trying to implement a CountDownTimer to post a visual text count-down until I get to 0, then send a specific message. Everything works fine until I get to 3 seconds, it calls the my done() method twice; once with 3 seconds left and once when the counter is done.
I am certain that the only time done() is called is when onFinish() in this CountDownTimer() is called. I have no clue why it is calling twice, and at consistently the same time.
My Java Code:
mainCounter = new CountDownTimer(30000, 1000){
#Override
public void onTick(long millisUntilDone){
int hours = (int) (millisUntilDone/3600000);
int mins = 0, secs = 0;
long timeLeft = millisUntilDone % 3600000;
if((int)timeLeft != 0){
mins = (int) (timeLeft/60000);
}
long timeLeftStill = timeLeft % 60000;
if((int)timeLeftStill != 0){
secs = (int) (timeLeftStill/1000);
}
((TextView)findViewById(R.id.timer_label)).setText("You have " + hours + " hours, " + mins + " mins, " + secs + " secs left");
}
#Override
public void onFinish() {
// Send Message, Out of Time
((TextView)findViewById(R.id.timer_label)).setText("MESSAGE!");
num++;
done(); //My Own Method
this.cancel();
}
}.start();
I have another counter that works perfectly, I have commented it out to ensure it doesn't affect this counter, and like I say this one works fine until I get to 3 second left.
For you problem concerning the call of onFinish() method when 3 seconds are left, you should read the answer here. Actually you should read all the answers on Android: CountDownTimer skips last onTick()! question. It will hep you understand the reason. Talking abou that thread, usually people have had problems where finish gets called approx. 1 second before the estimated time. For them it can be understood ( from the answer referenced) that at the start of every tick, before onTick() is called, the remaining time until the end of the countdown is calculated. If this time is smaller than the countdown time interval, onTick is not called anymore. But the answer there also states that there may be other processes in the background that delay the thread running CountDownTimer plus that Android itself will probably create a small delay when calling the message handler of CountDownTimer, so your undesired delay might be becauase of all that.
Few workaround have been suggested in the answers. One is either decreaseing the interval time or increasing the maximum countDownTimer value. There is also one alternative of countDownTimer method. Hope this helps you understand the possible reason and will aid you to do the workaround.
You can do like this
private int secondsLeft = 0;
private int minutes;
private int seconds;
private String timeString;
counter = new CountDownTimer(30000, 100) {
public void onTick(long ms) {
if (Math.round((float) ms / 1000.0f) != secondsLeft) {
secondsLeft = Math.round((float) ms / 1000.0f);
minutes = (secondsLeft % 3600) / 60;
seconds = secondsLeft % 60;
timeString = String.format("%02d:%02d", minutes, seconds);
textViewTimer.setText(timeString);
}
}
public void onFinish() {
textViewTimer.setText("00:00");
}
}.start();

Categories

Resources