What is the point of Apache Lang3 StopWatch.split()? - java

I am currently evaluating implementations between Apache StopWatch and Guava's Stopwatch and the split functionality in the former intrigued me, but I am struggling to understand what exactly it does, and what value it has.
According to the documentation for StopWatch: https://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/time/StopWatch.html
split() the watch to get the time whilst the watch continues in the background. unsplit() will remove the effect of the split. At this point, these three options are available again.
And I found some examples, such as this, which offer very little, since it appears split is just cumulative. The page says the method is for "splitting the time", which I figured as much based on the method, but the page makes no mention to what that actually means. It would even appear that this example is utterly wrong, because the docs suggest that you should unsplit before you split again.
I initially thought it was for the following usecase:
StopWatch stopwatch = StopWatch.createStarted();
do something for 5 seconds
stopwatch.split();
do something for 10 seconds
stopwatch.stop();
System.out.println(stopwatch.getTime());
System.out.println(stopwatch.getSplitTime());
I thought that stopwatch total time would read as 15 seconds, and stopwatch split time would read as either 10 or 5 seconds, but it appears that both methods output 15 seconds.
Next, I thought maybe the split value is a delta you can take, and then remove from the total timer, something like:
StopWatch stopwatch = StopWatch.createStarted();
do something for 5 seconds
stopwatch.split();
do something for 10 seconds
stopwatch.unsplit();
stopwatch.stop();
System.out.println(stopwatch.getTime());
// System.out.println(stopwatch.getSplitTime()); errors because of unsplit
My thought here was that the split time would be 10 seconds, and when unsplit from the main timer, the main timer would read as 5 seconds... but this seems no different from a suspend() call... I also tried this, and the timings remain the same nonetheless for me.
Am I missing something here, or is my interpretation of what this is supposed to do all wrong?

This is the source code for getSplitTime() (it calls this other function internally):
public long getSplitNanoTime() {
if (this.splitState != SplitState.SPLIT) {
throw new IllegalStateException("Stopwatch must be split to get the split time. ");
}
return this.stopTime - this.startTime;
}
So it will return stopTime-startTime. Beware of stopTime. It's the liar that's confusing you.
This is the code for stop():
public void stop() {
if (this.runningState != State.RUNNING && this.runningState != State.SUSPENDED) {
throw new IllegalStateException("Stopwatch is not running. ");
}
if (this.runningState == State.RUNNING)
{
//is this the same stopTime getSplitTime uses? yep, it is
this.stopTime = System.nanoTime();
}
this.runningState = State.STOPPED;
}
What's happenning then?
Calling stop() updates the stopTime variable and makes the stopwatch "forget" the last time it was splitted.
Both split() and stop() modify the same variable, stopTime, which is overrided when you call stop() at the end of your process.
Although sharing the same variable may look wierd, it really makes sense, as an splittedTime of an StopWatch should never be bigger than the total elapsed time. So it's a game regarding the order of the functions executed in the StopWatch.
This is the code for split(), in order to see that both methods do use stopTime:
public void split() {
if (this.runningState != State.RUNNING) {
throw new IllegalStateException("Stopwatch is not running. ");
}
this.stopTime = System.nanoTime(); // you again little f..
this.splitState = SplitState.SPLIT;
}
That's why this little adorable Apache liar shows you 15 seconds on the splittedTime: because stop() updated the stopTime variable getSplitTime() will use to return its value. (the first code snippet)
Note the simplicity of the split() function (this also barely answers OP's question). It is responsible of:
Checking wether the StopWatch is running.
Marking a new stopTime.
Setting the splitState to SPLIT.
TLDR lol
Calling getSplitTime() before stopping the StopWatch should show you the desired value:
stopTime won't be updated by stop() yet.
The returning value will now match the time elapsed between the last split() and the startTime.
Some examples: (yes, editing at saturday night cause I need a social life)
StopWatch stopwatch = StopWatch.createStarted();
do something for 5 seconds
stopwatch.split(); //stopTime is updated [by split()]
System.out.println(stopwatch.getSplitTime()); // will show 5 seconds
do something for 10 seconds
System.out.println(stopwatch.getSplitTime()); // will also show 5 seconds
stopwatch.stop(); //stopTime is updated again [by stop()]
System.out.println(stopwatch.getTime()); // 15s
System.out.println(stopwatch.getSplitTime()); // 15s
Another one:
StopWatch stopwatch = StopWatch.createStarted();
do something for 5 seconds
stopwatch.split();
System.out.println(stopwatch.getSplitTime()); // 5s
do something for 10 seconds
stopwatch.split();
System.out.println(stopwatch.getSplitTime()); // 15s
do something for 1 second
stopwatch.stop();
System.out.println(stopwatch.getTime()); // 16s
And a last one. Mocked the time with sleeps, just for the fun, you know. I was so bored I really imported the apache jar in order to test this locally:
StopWatch stopwatch = StopWatch.createStarted();
Thread.sleep(5000);
stopwatch.split();
System.out.println(stopwatch.getSplitTime()); // 5s
Thread.sleep(10000);
stopwatch.split();
System.out.println(stopwatch.getSplitTime()); // 15s
stopwatch.reset(); // allows the stopWatch to be started again
stopwatch.start(); // updates startTime
Thread.sleep(2000);
stopwatch.split();
System.out.println(stopwatch.getSplitTime()); // 2s
Thread.sleep(1000);
stopwatch.stop();
System.out.println(stopwatch.getTime()); // 3s
System.out.println(stopwatch.getSplitTime()); // 3s
//it was so fun putting the sleeps
Note that calling getSplitTime() on an stopped Watch won't throw any exception, because the method will only check wheter the splitState is SPLIT.
The confusion may be caused by these two facts:
The code allows you to stop() regardless of the SplitState, making your last split() futile without you being aware. Futile, I love that word. Had to include it in my answer somehow. Futileeee
It also allows you to check the splittedTime on an stopped watch (if it is still on SPLIT state), when it really just will return the total elapsed time between the last start() and the stopping time. (little liar)
In this scenario, where the stopwatch is stopped and splitted at the same time, getTime() and getSplitTime() will always show the same value when called after stop().
[Personal and subjective opinion]
Let's say you have a Counters class with different variables to check elapsed times. You also want to output the total elapsed time for each operation, every 60 seconds . In this example, counters is an instance of a Counters class that owns two long variables: fileTime and sendTime, that will accumulate the elapsed time within each operation during an specific interval (60s). This is just an example that assumes each iteration takes less than 1000 ms (so it will always show 60 seconds on the elapsed time):
long statsTimer = System.currentTimeMillis();
while (mustWork)
{
long elapsedStatsTimer = System.currentTimeMillis()-statsTimer; //hits 60185
if (elapsedStatsTimer > 60000)
{
//counters.showTimes()
System.out.println("Showing elapsed times for the last "+
(elapsedStatsTimer/1000)+ " secs"); //(60185/1000) - 60 secs
System.out.println("Files time: "+counters.fileTime+" ms"); //23695 ms
System.out.println("Send time : "+counters.sendTime+" ms"); //36280 ms
long workTime = counters.sendTime+counters.fileTime;
System.out.println("Work time : "+workTime+" ms"); //59975 ms
System.out.println("Others : "+(elapsedStatsTimer-workTime)+" ms"); //210 ms
//counters.reset()
counters.fileTime=0;
counters.sendTime=0;
statsTimer= System.currentTimeMillis();
}
long timer = System.currentTimeMillis();
//do something with a file
counters.fileTime+=System.currentTimeMillis-timer;
timer = System.currentTimeMillis();
//send a message
counters.sendTime+=System.currentTimeMillis()-timer;
}
That Counters class could implement the reset() and showTimes() functions, in order to clean up the code above. It could also manage the elapsedStatsTimer variable. This is just an example to simplify its behaviour.
For this use case, in which you need to measure different operations persistently, I think this way is easier to use and seems to have a similar performance, as the StopWatch internally makes the exact same thing. But hey, it's just my way to do it : ).
I will accept downvotes for this opinion in an honorable and futile way.
I would love to finish with a minute of silence in honour of unsplit(), which may be one of the most irrelevant methods ever existed.
[/Personal and subjective opinion]
Just noticed TLDR section is actually bigger than the previous section :_ )

Related

What is the most efficient way to simulate a countdown in java?

I want to print to the console every second. So far, I've been able to think of two ways to do this.
long start_time = System.currentTimeMillis();
while(true){
if ((System.currentTimeMillis() - start_time) >= 1000) {
System.out.println("One second passed");
start_time = System.currentTimeMillis();
}
}
And this
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("One second passed");
}
Is any method safer or more reliable or more efficient than the other?
or maybe there are use cases for each?
Thanks
This is not as simple as it seems.
The problem with your solutions are that the first is very inefficient, and the second is liable to drift because sleep(1000) does not guarantee to sleep for exactly 1 second. (The javadoc says that sleep(1000) sleeps for at least one second.)
One possibility is to use ScheduledExecutorService.scheduleWithFixedDelay and compute the delay each time by looking at the difference between the millisecond clock and your start time (or end time). That will keep your messages in sync with real time (more or less).
Or maybe you can simplify that using scheduleAtFixedRate, because it looks like ScheduledThreadPoolExecutor will take care of the clock syncing problem.
Another possibility is to look for a 3rd-party library that implements a "cron-like" scheduler in Java.

How can I await at least specified amount of time with Awaitility?

I my test class I really need to sleep for some amount of time. It's an integration test involving periodic remote call.
for (int i = 0; i < 16; i++) {
// sleep some... should sleep some...
Thread.sleep((int) TimeUnit.MINUTES.toMillis(4L)); // means as it means.
// call remote api and check the response.
}
And what is the equivalent expression using Awaitility?
I tried...
// Let's sleep for 4 minutes, no matter what happen!
Awaitility.await()
.atLeast(Duration.ofMinutes(4L)) // what the hell does this mean, anyway?
.untilTrue(new AtomicBoolean(false));
It seems the timeout fired just after the default polling interval.
Shouldn't I use the Awaitillity at the first time in this case?
Probably too late of an answer but there are several ways to do it.
This tells awaitility to have a poll delay of 4 minutes. So, wait 4 minutes before doing the assertion.
Awaitility.await().pollDelay(4, TimeUnit.MINUTES).untilAsserted(() -> Assert.assertTrue(true));

How can I run a method repeatedly for a set amount of time?

I've been using Schedule Executor service to run my code every 3 seconds. Is there a way to run it every 3 seconds for 24 hours in my case? My code looks something like this. It isn't important what it does so I've just removed it all. The only part I care about is one List<String> and the reason for that is after this 24 hour period I would then like to do some more stuff with this list.
public static void main(String[] args) throws Exception {
ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);
ses.scheduleWithFixedDelay(new Runnable() {
// nonImportantVariables here
List<String> importantList = new ArrayList<String>();
public void run() {
//Not important code
}, 0, 3, TimeUnit.SECONDS);
// AFTER 24 HOURS I WOULD LIKE TO PERFORM TASKS ON IMPORTANT LIST
}
}
I've thought about adding a loop so it runs 28,800 times (that is how many 3 seconds are in 24 hours) but this seems a silly fix around and also I'd run into the issue that this wouldn't account for how long the code takes to run so would end up being more.
A second idea I had was the first time the iteration is run I can use a Date object. Using this Date object I could somehow add 24 hours onto this and have some method that compares the current Date object to the Date object at first iteration + 24 hours.
I can't seem to find anything in the documentation of Schedule executor service where I can set how many times to run a command. Any improvements to either of these ideas or a different solution is much appreciated thanks.
You can use another scheduler and in it you can submit another task that would run just once with a delay of 24 hours and it will do 2 things.
shutdown the first scheduler and that will stop the execution of your original task.
handle the processing of your list

Java - repeatedly run a function in a given number of milliseconds accurately?

Does anyone have a Fairly effective way of running a function repetitively in a precise and accurate number of milliseconds. I have tried to accomplish this by using the code below to try to run a function called wave() once a second for 30 seconds:
startTime = System.nanoTime();
wholeTime = System.nanoTime();
while (loop) {
if (startTime >= time2) {
startTime = System.nanoTime();
wave();
sec++;
}
if (sec == 30) {
loop = false;
endTime = System.nanoTime();
System.out.println(wholeTime - System.nanoTime());
}
}
}
This code did not work and am wondering why this code didn't work and if their is a better approach to the problem. Any ideas on how to improve fix the above code or other successful ways of accomplishing the problem are all welcome. Thank you for your help!
more simple:
long start=System.currentTimeMillis(); // Not very very accurate
while (System.currentTimeMillis()-start<30000)
{
wave();
// count something
}
You can use a Timer+TimerTask: https://docs.oracle.com/javase/7/docs/api/java/util/Timer.html
https://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html
http://bioportal.weizmann.ac.il/course/prog2/tutorial/essential/threads/timer.html
You may use Thread.sleep():
public static void main (String[] args) throws InterruptedException {
int count = 30;
long start = System.currentTimeMillis();
for(int i=0; i<count; i++) {
wave();
// how many milliseconds till the end of the second?
long sleep = start+(i+1)*1000-System.currentTimeMillis();
if(sleep > 0) // condition might be false if wave() runs longer than second
Thread.sleep(sleep);
}
}
Does anyone have a Fairly effective way of running a function repetitively in a precise and accurate number of milliseconds.
There is no way to do this kind of thing reliably and accurately in standard Java. The problem is that there is no way that you can guarantee that your thread will run when you want ti to run. For example:
your thread could be suspended to allow the GC to run
your thread could be preempted to allow another thread in your application to run
your thread could be suspended by the OS while it fetches pages by the JVM back from disk.
You can only get reliable behavior for this kind of code if you run on a hard realtime OS, and an realtime Java.
Note that this is not an issue with clock accuracy. The real problem is that the scheduler does not give you the kind of guarantees you need. For instance, none of the "sleep until X" functionality in a JVM can guarantee that your thread will wake up at time X exactly ... for any useful meaning of "exactly".
The other answers suggest various ways to do this, but beware that they are not (and cannot be) reliable and accurate in all circumstances .. or even on a typical machine running other things as well as your application.

How to use the current time in a Java Program?

Say, for example, I want to run the following program
double x = 15.6
System.out.println(x);
But I wanted to repeat the program until a certain time has elapsed, such as the following:
do{
double x = 15.6
System.out.println(x);
}while (current time is earlier than 12.00pm)
Even though the example is completely hypothetical, how would I make that do while loop so that the program would keep running over and over again until a certain time, say 3pm, or9.30pm.
If this is not possible, is there any way I can simulate this, by running the program every so many seconds, until that time has been reached?
a) You usually don't need the code to actually run until a time has come - you wouldn't have any control over the amount of times the code executed this way. Regular code has to sleep sometimes, to give control to OS and other processes so that they don't clog the system with 100% CPU load. As such, actually running the code constantly is a wrong approach to 99% of the possible problems related to timings. Please describe the exact problem you want to solve using this code.
b) For those 99% of problems, use a Timer instance. Simple as that. https://docs.oracle.com/javase/7/docs/api/java/util/Timer.html - schedule the task to run e.g. 1000 times a second, and check the time in each event, terminating the Timer instance when the time threshold has been exceeded.
For example, this code above will give you continuous execution of Do something part, every 1 second, until 16.11.2014 20:00 GMT. By changing delayMs you can easily achieve higher/lower time granularity. If you expect your code to be run more often than 1000/sec, you should probably use JNI anyway, since Java timers/clocks are known to have <10ms granularity on some (older) platforms, see How can I measure time with microsecond precision in Java? etc.
Timer timer = new Timer();
int delayMs = 1000; // check time every one second
long timeToStop;
try {
timeToStop = new SimpleDateFormat( "DD.MM.YYYY HH:mm" ).parse( "16.11.2014 20:00" ).getTime(); // GMT time, needs to be offset by TZ
} catch (ParseException ex) {
throw new RuntimeException( ex );
}
timer.scheduleAtFixedRate( new TimerTask() {
#Override
public void run() {
if ( System.currentTimeMillis() < timeToStop ) {
System.out.println( "Do something every " + delayMs + " milliseconds" );
} else {
timer.cancel();
}
}
}, 0, delayMs );
or you can use e.g. ExecutorService service = Executors.newSingleThreadExecutor(); etc. - but it's virtually impossible to give you a good way to solve your problem without explicitly knowing what the problem is.
Something like this
//get a Date object for the time to stop, then get milliseconds
long timeToStop = new SimpleDateFormat("DD:MM:HH:mm").parse("16:11:12:00").getTime();
//get milliseconds now, and compare to milliseconds from before
do {
//do stuff
} while(System.currentTimeMillis() < timeToStop)

Categories