Interrupt Loop after some Time in Java - 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?

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.

Why this while loop cannot print 1,000 times per seconds?

The following Java method is meant to print the number i by nLoopsPerSecond times per second for seconds seconds:
public void test(int nLoopsPerSecond, int seconds) {
double secondsPerLoop = 1.0/(double)nLoopsPerSecond;
long startTime = System.currentTimeMillis();
long currentTime;
int i = 0;
while ((currentTime = System.currentTimeMillis()) < startTime + seconds*1000) {
System.out.println(i++);
while (System.currentTimeMillis() < currentTime + secondsPerLoop*1000);
}
}
With the following call:
test(1000,1);
I expect this method to do the System.out.println(i++); 1,000 times, but I only got 63.
When I try to see how many seconds it actually use per loop with this code
public void test(int nLoopsPerSecond, int seconds) {
double secondsPerLoop = 1.0/(double)nLoopsPerSecond;
long startTime = System.currentTimeMillis();
long currentTime;
int i = 0;
while ((currentTime = System.currentTimeMillis()) < startTime + seconds*1000) {
while (System.currentTimeMillis() < currentTime + secondsPerLoop*1000);
System.out.println(System.currentTimeMillis() - currentTime);
}
}
I expect it to print 1 milliseconds each loop, but it prints 15 or 16 milliseconds.
Please suggest what is wrong in my code.
Are you running on Windows, perhaps? System.currentTimeMillis() consults the underlying operating system clock, which is only 60Hz on many versions of Windows.
Try System.nanoTime() since you are not measuring time since the epoch. System.currentTimeMillis vs System.nanoTime
That's probably because the processing takes up some time. The processor does not solely dedicate its time to the execution of your program, it performs several other functions in the background. So you might get different results based on the processor load.
Your output console is not fast enough. You do not mention how you run your test and where the output goes. The speed of the terminal and buffers (not) used will limit how fast can the program output data. If running unbuffered, your program will always have to wait, until the new line is printed on screen. If the console waits for screen redraw and screen is redrawn at 60Hz, you've got your 16ms/line and about 60 lines per second.
Running your code without inner loop inside IntelliJ Idea, I get about 140.000 lines per second (and Idea warns me, that it is not displaying every line, as my output is too fast).
With the inner loop, I get about 800-900 lines. That happens because the process may be scheduled out of cpu, or blocked because of something else, like swapping. (If I simplify a lot, usually desktop OSes schedule in 1ms granularity.)

LWJGL timer not working?

I keep getting a lot of "Delta: 0.0"s in my console and ever few lines I get something like "Delta: 9.999275207519531E-4", what's happening?
Timer timer = new Timer();
float lastTime = 0.0f;
timer.resume();
while (!Display.isCloseRequested())
{
timer.tick();
System.out.println("Delta: " + (timer.getTime() - lastTime));
lastTime = timer.getTime();
Display.update();
}
Display.destroy();
Don't ever use java's Timer class in your game loops. It isn't precise enough to use reliably. Instead, check out this link to see a couple of reliable game loops written in java.
One little note, just a warning. Your timing mechanism is flawed a bit.
Considering this code runs line by line as it is written, you'll "loose" time. This
System.out.println("Delta: " + (timer.getTime() - lastTime));
lastTime = timer.getTime();
code does the following:
1. Getting current time.
2. Doing some math.
3. Calling String constructor.
4. Performing String concatenation.
5. Writing current time to the lastTime variable.
Note that current time in the 1 and 5 cases are different. That means that this time is "lost" from the "Delay: xx" output.
If you continue to use (timer.getTime() - lastTime) technics in your code for the purpose of getting time passed from the previous iteration, you will surely run into problem where different events thinks that time passed from the previous iteration is different. I recommend you to use the following code for timing:
private double delta;
private long timing;
public void updateTime()
{
long newTime = System.nanoTime();
this.delta = (newTime - this.timing) / 1_000_000_000.0;
this.timing = newTime;
}
public double getDelta() {
return this.delta;
}
where updateTime() is called once per cycle and getDelta() is called every time you want to get time passed from the previous iteration.

Measure execution time for a Java method [duplicate]

This question already has answers here:
How do I time a method's execution in Java?
(42 answers)
Closed 9 years ago.
How do I calculate the time taken for the execution of a method in Java?
To be more precise, I would use nanoTime() method rather than currentTimeMillis():
long startTime = System.nanoTime();
myCall();
long stopTime = System.nanoTime();
System.out.println(stopTime - startTime);
In Java 8 (output format is ISO-8601):
Instant start = Instant.now();
Thread.sleep(63553);
Instant end = Instant.now();
System.out.println(Duration.between(start, end)); // prints PT1M3.553S
Guava Stopwatch:
Stopwatch stopwatch = Stopwatch.createStarted();
myCall();
stopwatch.stop(); // optional
System.out.println("Time elapsed: "+ stopwatch.elapsed(TimeUnit.MILLISECONDS));
You can take timestamp snapshots before and after, then repeat the experiments several times to average to results. There are also profilers that can do this for you.
From "Java Platform Performance: Strategies and Tactics" book:
With System.currentTimeMillis()
class TimeTest1 {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
long total = 0;
for (int i = 0; i < 10000000; i++) {
total += i;
}
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
System.out.println(elapsedTime);
}
}
With a StopWatch class
You can use this StopWatch class, and call start() and stop before and after the method.
class TimeTest2 {
public static void main(String[] args) {
Stopwatch timer = new Stopwatch().start();
long total = 0;
for (int i = 0; i < 10000000; i++) {
total += i;
}
timer.stop();
System.out.println(timer.getElapsedTime());
}
}
See here (archived).
NetBeans Profiler:
Application Performance Application
Performance profiles method-level CPU
performance (execution time). You can
choose to profile the entire
application or a part of the
application.
See here.
Check this: System.currentTimeMillis.
With this you can calculate the time of your method by doing:
long start = System.currentTimeMillis();
class.method();
long time = System.currentTimeMillis() - start;
In case you develop applications for Android you should try out the TimingLogger class.
Take a look at these articles describing the usage of the TimingLogger helper class:
Measuring performance in the Android SDK (27.09.2010)
Discovering the Android API - Part 1 (03.01.2017)
You might want to think about aspect-oriented programming. You don't want to litter your code with timings. You want to be able to turn them off and on declaratively.
If you use Spring, take a look at their MethodInterceptor class.
If you are currently writing the application, than the answer is to use System.currentTimeMillis or System.nanoTime serve the purpose as pointed by people above.
But if you have already written the code, and you don't want to change it its better to use Spring's method interceptors. So for instance your service is :
public class MyService {
public void doSomething() {
for (int i = 1; i < 10000; i++) {
System.out.println("i=" + i);
}
}
}
To avoid changing the service, you can write your own method interceptor:
public class ServiceMethodInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = methodInvocation.proceed();
long duration = System.currentTimeMillis() - startTime;
Method method = methodInvocation.getMethod();
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
System.out.println("Method '" + methodName + "' took " + duration + " milliseconds to run");
return null;
}
}
Also there are open source APIs available for Java, e.g. BTrace.
or Netbeans profiler as suggested above by #bakkal and #Saikikos.
Thanks.
As proposed nanoTime () is very precise on short time scales.
When this precision is required you need to take care about what you really measure.
Especially not to measure the nanotime call itself
long start1 = System.nanoTime();
// maybe add here a call to a return to remove call up time, too.
// Avoid optimization
long start2 = System.nanoTime();
myCall();
long stop = System.nanoTime();
long diff = stop - 2*start2 + start1;
System.out.println(diff + " ns");
By the way, you will measure different values for the same call due to
other load on your computer (background, network, mouse movement, interrupts, task switching, threads)
cache fillings (cold, warm)
jit compiling (no optimization, performance hit due to running the compiler, performance boost due to compiler (but sometimes code with jit is slower than without!))
Nanotime is in fact not even good for elapsed time because it drifts away signficantly more than currentTimeMillis. Furthermore nanotime tends to provide excessive precision at the expense of accuracy. It is therefore highly inconsistent,and needs refinement.
For any time measuring process,currentTimeMillis (though almost as bad), does better in terms of balancing accuracy and precision.

Categories

Resources