What is the difference between schedule and scheduleAtFixedRate? - java

What is the difference between these 2 methods of Timer class :
schedule(TimerTask task, long delay, long period)
and
scheduleAtFixedRate(TimerTask task, long delay, long period)
Documentation doesn't make the difference between them clear.

The documentation does explain the difference:
schedule:
In fixed-delay execution, each execution is scheduled relative to the actual execution time of the previous execution. If an execution is delayed for any reason (such as garbage collection or other background activity), subsequent executions will be delayed as well.
So, suppose the delay is 5 seconds, and each task takes 2 seconds, you would get
TTWWWTTWWWTTWWWTT
where T means 1 second for the task execution, and W means 1 second waiting.
But now suppose that a long GC (represented by a G) happens and delays the second task, the third one will start 5 seconds after the start of the second one, as if the long GC didn't happen:
TTWWWGGTTWWWTTWWWTT
The third task starts 5 seconds after the second one.
scheduleAtFixedRate:
In fixed-rate execution, each execution is scheduled relative to the scheduled execution time of the initial execution. If an execution is delayed for any reason (such as garbage collection or other background activity), two or more executions will occur in rapid succession to "catch up.".
So, with the same delay as above, and the same GC, you would get
TTWWWGGTTWTTWWWTT
The third task task starts 3 seconds instead of 5 after the second one, to catch up.

Thanks #Nizet's answer, I have written a sample code for some people who want to practice and learn.
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest {
public static void main(String args[]){
TimerTest.DelayTask task = new DelayTask();
Timer timer = new Timer();
/**
* Use schedule or scheduletAtFixedrate and check the printed result
*/
timer.schedule(task, 0, 5000);
//timer.scheduleAtFixedRate(task, 0, 5000);
}
public static boolean stop = false;
public static void delayOneSec(String status){
try{
System.out.print(status);
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
}
static class DelayTask extends TimerTask{
int count = 2;
#Override
public void run() {
// TODO Auto-generated method stub
stop = true;
for(int i = 0; i < count; i++){
TimerTest.delayOneSec("T");
}
if(count == 2){
count = 6;
}else{
count = 2;
}
stop = false;
new PrintW().start();
}
}
static class PrintW extends Thread{
#Override
public void run(){
while(!stop){
TimerTest.delayOneSec("W");
}
}
}
}
The task itself will repeat to take 2 seconds or 6 seconds. Let's see the result of each scenario.
When using timer.schedule(task, 0, 5000);, the output is TTWWWTTTTTTTTWWWTTTTTTTTWWWTTTTTTTT. As you can see, the timer follow the rules like below, wait till period time outs if task finishes in time, launch next task immediately if current task lasts more than period.
When using timer.scheduleAtFixedRate(task, 0, 5000);, the output is TTWWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTTWWTTTTTTTT. Things are a little different now. The javadoc
two or more executions will occur in rapid succession to "catch up."
takes effect here. As you can see, ignoring the first TTWWW, every two tasks will print TTTTTTTTWW and it lasts 10 seconds(two periods).
Let's dig into the source code of Timer.
public void schedule(TimerTask task, Date firstTime, long period) {
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, firstTime.getTime(), -period);
}
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, System.currentTimeMillis()+delay, period);
}
As you can see, the period is transferred to negative value in schedule method. Let's see what's the difference when scheduling it.
The below code is in the mainloop of TimerThread,
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if (taskFired = (executionTime<=currentTime)) {
if (task.period == 0) { // Non-repeating, remove
queue.removeMin();
task.state = TimerTask.EXECUTED;
} else { // Repeating task, reschedule
queue.rescheduleMin(
task.period<0 ? currentTime - task.period
: executionTime + task.period);
}
}
}
It's where magic happens, for schedule method, the next task execution time is based on the currentTime which is calculated right before the this task runs. That means, every task's execution time only be related with previous task starts time.

Related

Accurate thread loop. Run a task with precise interval

I want my thread to perform an action 4 or 16 times per bpm (beats per minute). This timer is not 100% accurate, after a few seconds it desynchronizes from the metronome I found on youtube, and it gets a little slower than it should.
bpm = (float) my music bpm;
thread = new Thread(()->{
long now ;
long total ;
while (true) {
long bpmTime = (long) ((1000000000*60d)/(bpm*16));
now = System.nanoTime();
bpmTick(); //<-- my task
try {
total = System.nanoTime() - now;
if(total > bpmTime) {
continue;
}
Thread.sleep((bpmTime - (System.nanoTime() - now)) / 1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
I also tried:
Thread.sleep((long)(1000*(60.0/bpm)));
but the same problem occurs
In short, I need a metronome.
Thanks in advance.
What you want to use is a ScheduledExecutorService instance instead. This class can repeat the task in a Thread repeatedly at a fixed rate. The class has a method called scheduleAtFixedRate(task, intialDelay, DelayBetweenExecutions,TimeUnit) just for this purpose.
When the initial delay is set to 0 the task will run as soon as scheduleAtFixedRate is called and will continue doing so until you call shutdown() or shutdownNow() on the service. Here's an example that uses some of your code:
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
int timesPerBPM = 16;
long bpmTime = 900; //or whatever the outcome of your formula is.
Thread thread = new Thread(()->{
for (int i = 0; i < timesPerBPM; i++) //do task 16 times
bpmTick(); //<-- my task
});
executorService.scheduleAtFixedRate(thread, 0, bpmTime, TimeUnit.MILLISECONDS); //This will start immediately because initialDelay is 0.
executorService.shutdown(); //Always shutdown service when done to avoid memory leaks.
The executorService in the below code will run bpmTick() 16 times every 900 milliseconds. If it takes longer then 900 milliseconds to run bpmTick() 16 times the service will wait for the current task to complete until it starts the next repetition. So to keep things synchronized the 16 bpmTick() must always finish within bpmTime milliseconds. If you want to guarantee a 150 millisecond pause between threadtask executions regardless of how long it takes to execute a task then you should use the method scheduleWithFixedDelay() instead.
If you want the service to repeat the task every minute instead of every 900 milliseconds then it is best to change bpmTime to 1 and TimeUnit.MILLISECONDS to TimeUnit.MINUTES.

Schedule a job to run at multiple of 2 seconds i.e 2,4,8,16,32 seconds

I want to Schedule a job to run at multiple of 2 seconds, which is 2,4,8,16,32 seconds. Second fire should happen after two seconds of completion of first fire, Third fire should happen after 4 seconds of completion of second fire and so on. The next fire is based on status we get from previous fire, based on which it will be decided whether we need to trigger next fire or not.
Can somebody tell me how can I use quartz scheduler to achieve this?
If I use SimpleTrigger.withIntervalInSeconds(2) it runs a job after every 2 seconds where as I want time interval should be increased with multiple of 2 in every firing.
Perhaps you could forget trying to set up a single trigger, but use multiple triggers. My Java is not good in this area, so this is in pseudocode:
delay = 2
repeat
TriggerOnceAfter(delay)
delay <- delay * 2
WaitUntilTriggered()
until (finished)
I am not sure how to implement the WaitUntilTriggered() method; you my need to add a signalling flag to the triggered code for WaitUntilTriggered() to look at.
That will give delays of 2, 4, 8, ...
This is a simplified implementation that will invoke a Runnable at the requested schedule:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Tasker {
private int numberOfRuns; //how many times job executed
private int timeBetweenRuns;//seconds
Tasker(int numberOfRuns){
this.numberOfRuns = numberOfRuns;
timeBetweenRuns = 2;
execute();
}
private void execute() {
for (int counter = 0; counter < numberOfRuns ; counter++) {
CountDownLatch latch = new CountDownLatch(1);
Job job = new Job(latch, timeBetweenRuns);
job.run();
try {
latch.await();
TimeUnit.SECONDS.sleep(timeBetweenRuns);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
timeBetweenRuns *=2;
}
}
public static void main(String[] args){
new Tasker(5);
}
}
class Job implements Runnable {
private int seconds;
private CountDownLatch latch ;
Job(CountDownLatch latch , int seconds){
this.latch = latch;
this.seconds = seconds;
}
#Override
public void run() {
System.out.println("Job runs "+ seconds +" after previous one");
latch.countDown();
}
}

Synchronise to beats per minute / Send quantised messages

I'm getting periodic signals (beats per minute) from a Transmitter and now want to call methods in a fraction of the period, e.g. send 1/1, 1/2, 1/4, 1/8, 1/16,.. notes.
My solution for this is to create a thread, do a busy wait and then execute the methods. The problem here is that listening to the signal, processing it and sending it back creates a delay of a few milliseconds (depending on the system).
So now I want to determine the delay between the incoming signal and the periodic signal of the thread and if the delay is != 0, stop the current thread and start a new thread after "bpm - delay" milliseconds. How can this be done ?
Illustration:
transmitter signal: |----|----|----|----|
******runner signal : |----|----|----|----|
delay runner signal by "onePeriod - delay" milliseconds:
transmitter signal: |----|----|----|----|
***"runner signal :**** |----|----|----|----|
Both signals are now in sync.
public class Quantiser implements Receiver{
private int[] bpmsInMillis = new int[4];
private int bpmInMillis=0;
private double smallestNote = 1;
private long period=0;
private long fire=0;
private long prevTimeStamp=0;
private Runnable runny = new Runnable() {
#Override
public void run() {
while(true){
fire = System.nanoTime() + period;
while(System.nanoTime() < fire){} // busy wait
// Call some methods here.
}
}
};
private Thread thread = new Thread(runny);
#Override
public void send(MidiMessage message, long timeStamp) {
// Calculate average bpm
for(int i=0; i<bpmsInMillis.length-1;i++)
bpmsInMillis[i] = bpmsInMillis[i+1];
bpmsInMillis[bpmsInMillis.length-1] = (int) ((timeStamp - prevTimeStamp) / 1000);
bpmInMillis = arithmeticMean(bpmsInMillis);
prevTimeStamp = timeStamp;
period = (long) (bpmInMillis * smallestNote * 1000000);
if(!thread.isAlive()) {
thread.start();
}
/*
else{
Calculate delay between signal and thread-signal.
if(delay != 0){
Delay new thread by "bpm - delay" milliseconds.
Stop old thread.
Start new thread.
}
*/
}
#Override
public void close() {
}
One option would be to implment a Phase-Locked Loop (PLL).
http://en.wikipedia.org/wiki/Phase-locked_loop
Basically, you'll need two threads: One thread sits in a loop waiting for the input beats, and each time it gets a beat, it records the time of arrival.
long time_of_last_beat;
while (true) {
wait_for_next_beat();
time_of_last_beat = System.currentTimeMillis();
}
The other thread sits in a loop that goes sixteen times as fast:
long semiquaver_duration = <starting guess>;
while (true) {
notify_whoever_cares_that_its_time_for_the_next_semiquaver();
Thread.sleep(sixteenth_note_duration);
long phase_error = System.currentTimeMillis() - time_of_last_beat;
semiquaver_duration += estimate_phase_correction(phase_error);
}
I'll leave it to you to write the estimate_phase_correction() function. A linear function of the given error with the right coefficient may be all you need. If you get it right, the 16x loop should "lock in" so that every sixteenth semiquaver happens exactly on the beat.
Improvements:
have the beat loop compute the tempo.Base the starting guess for the semiquaver period on the current tempo.Notice significant (i.e. abrupt) tempo changes and re-set the semiquaver loop as needed.
In general, when I work with sound (usually sampled, not MIDI), I find it more accurate to use frame counts than elapsed time. With elapsed time there are too many unknowns (thread slicing, garbage collection, etc.). Latencies may vary, but 44100 frames (if that is the format) is always 1 sec.
With MIDI, doesn't every event have a field with the time that event is supposed to occur? I've seen readouts with both beats/measures and elapsed-time. I would use that info rather real-time time stamps when figuring any sort of positioning onto an existing Midi stream.
If this is something where the incoming is ASAP/real time, but you want to pass it through quantised, can you put scheduling info on the out-going Midi even if the incoming doesn't have it? Then you'd have a solid reference points for the positioning.
Reference on Real-Time. Low Latency Audio Processing in Java:
https://diuf.unifr.ch/main/pai/sites/diuf.unifr.ch.main.pai/files/publications/2007_Juillerat_Mueller_Schubiger-Banz_Real_Time.pdf

Running a java code repeatedly for a given duration in Jenkins

I want to run java code for a certain duration ,say 16 hours! I have a java code that runs for approximately an hour.I want this to run repeatedly for 16 hours. So I have a parameter that is passed by the user through Jenkins ! I access this value using
System.getenv("Duration");
Now, I want to exit the execution after the specified time. So suppose the user selected 16, the script should run for 16 hours and then exit.
Accepting input from Jenkins user as shown in the image
I saw some other questions, but most of them were dealing with timers for either few seconds or few minutes. I need an efficient solution. Thanks :)
FYI - Environment - Jenkins+TestNG+Maven+Java
EDIT :
long start = System.currentTimeMillis();
long end = start + durationInHours*60*60*1000;
while (System.currentTimeMillis() < end)
{
//My code here runs for approx. 50 mins!
}
Now suppose the user chooses the value 3 hours, I want the while loop to exit after 3 hours. But this does not happen as it has not yet completed 3 hours when checking the while condition.So it enters the while condition even the 4th time(since time elapsed is 150 mins which is less than 180 mins) it ends after 3 hours ten mins.
How to make it exit the while loop as soon as 180 mins is reached ?
P.S - I could do the math first,( iterations =durationFromUser/codeDuration) and then run a for loop, but I don't want to do this as my script length may vary.
EDIT 2:
boolean alive = true;
Timer timer = new Timer();
#Test() //Annotation from TestNG
public void public void jenkinsEntryPoint()
{
String duration = System.getenv("Duration");
int durationInHours=Integer.parseInt(duration);
long end = System.currentTimeMillis() + durationInHours*60*60*1000;
TimerTask task = new TimerTask() {
public void run() {
alive = false;
};
timer.schedule(task, end);
while (alive) {
//My code here runs for approx. 50 mins!
function1();
}
}
void function1() {
function2();
}
private void function2() {
for(i=0;i<8;i++)
{
while(alive)
{
//long running code
sleep(1000);
//Some more code
sleep(2000);
//Some more code
//Suppose time elapses here, I want it to quit
//But its continuing to execute
.
.
.
.
}
}
}
The while condition will only be evaluated between script invocations (as you've seen). You will have to break out of your long running from inside of it.
I would typically use a Timer to set a "global" boolean that you would check from inside the loops in your long running code.
Something like this. Notice checks against 'alive' would have to be in all you long loops...
boolean alive = true;
Timer timer = new Timer();
public void jenkinsEntryPoint()
long end = System.currentTimeMillis() + durationInHours*60*60*1000;
TimerTask task = new TimerTask() {
public void run() {
alive = false;
};
timer.schedule(task, end);
while (alive) {
//My code here runs for approx. 50 mins!
yourLongRunningCode()
}
public void yourLongRunningCode() {
while (alive) {
doStuff();
}
}
I tried ScheduledThreadPoolExecutor and it worked!
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
exec.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("Time's Up According To ScheduledThreadPool");
alive = false;
}
}, durationInHours, 1, TimeUnit.HOURS);
This function will be executed after "durationInHours".
Thanks #TedBigham :)

How to run java function for only 30 minutes

I need to create a java function that will only run for 30 minutes, and at the end of the 30 minutes it executes something. But it should also be able to self terminate before the given time if the right conditions are met. I don't want the function to be sleeping as it should be collecting data, so no sleeping threads.
Thanks
Use: Timer.schedule( TimerTask, long )
public void someFunctino() {
// set the timeout
// this will stop this function in 30 minutes
long in30Minutes = 30 * 60 * 1000;
Timer timer = new Timer();
timer.schedule( new TimerTask(){
public void run() {
if( conditionsAreMet() ) {
System.exit(0);
}
}
}, in30Minutes );
// do the work...
.... work for n time, it would be stoped in 30 minutes at most
... code code code
}
Get the start time with System.currentTimeMillis(), calculate the time when to stop and check the current time every now and then while you're collecting the data you want to collect. Another way would be to decouple the timer and the data collecting, so that each of them could run in their own threads.
For a more specific answer, it would be helpful if you would tell what data you are collecting and how you are collecting it.
Something like this will work:
long startTime = System.currentTimeMillis();
long maxDurationInMilliseconds = 30 * 60 * 1000;
while (System.currentTimeMillis() < startTime + maxDurationInMilliseconds) {
// carry on running - 30 minutes hasn't elapsed yet
if (someOtherConditionIsMet) {
// stop running early
break;
}
}
The modern java.util.concurrent way would be using ExecutorService. There are several invoke methods taking a timeout.
Here's a kickoff example:
public static void main(String args[]) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.invokeAll(Arrays.asList(new Task()), 30, TimeUnit.MINUTES);
executor.shutdown();
}
where Task look like this:
public class Task implements Callable<String> {
#Override
public String call() {
// Just a dummy long running task.
BigInteger i = new BigInteger("0");
for (long l = 0; l < Long.MAX_VALUE; l++) {
i.multiply(new BigInteger(String.valueOf(l)));
// You need to check this regularly..
if (Thread.interrupted()) {
System.out.println("Task interrupted!");
break; // ..and stop the task whenever Thread is interrupted.
}
}
return null; // Or whatever you'd like to use as return value.
}
}
See also:
Lesson: Concurrency

Categories

Resources