Accurate thread loop. Run a task with precise interval - java

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.

Related

ScheduledExecutorService wait to perform tasks before the countdown to the next [duplicate]

What's the main difference between scheduleAtFixedRate and scheduleWithFixedDelay methods of ScheduledExecutorService?
scheduler.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
System.out.println("scheduleAtFixedRate: " + new Date());
}
}, 1, 3L , SECONDS);
scheduler.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
System.out.println("scheduleWithFixedDelay: " + new Date());
}
}, 1, 3L , SECONDS);
they print exact the same time, seems they are executed at exact the same interval.
Try adding a Thread.sleep(1000); call within your run() method... Basically it's the difference between scheduling something based on when the previous execution ends and when it (logically) starts.
For example, suppose I schedule an alarm to go off with a fixed rate of once an hour, and every time it goes off, I have a cup of coffee, which takes 10 minutes. Suppose that starts at midnight, I'd have:
00:00: Start making coffee
00:10: Finish making coffee
01:00: Start making coffee
01:10: Finish making coffee
02:00: Start making coffee
02:10: Finish making coffee
If I schedule with a fixed delay of one hour, I'd have:
00:00: Start making coffee
00:10: Finish making coffee
01:10: Start making coffee
01:20: Finish making coffee
02:20: Start making coffee
02:30: Finish making coffee
Which one you want depends on your task.
Visualize time series of invocation scheduleAtFixedRate method. Next executions will start immediately if the last one takes longer than period. Otherwise, it will start after period time.
Time series of invocation scheduleWithFixedDelay method. Next execution will start after delay time between termination of one execution and the commencement of the next, regardless of its execution time
Hope can help you
The scheduleAtFixedRate() method creates a new task and submits it to the executor every period, regardless of whether or not the previous task finished.
On the other hand, the scheduleWithFixedDelay() method creates a new task after the previous task has finished.
If you read the Java Doc it will be clearer
ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.
ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next.
There is one catch in scheduleAtFixedRate if first thread is taking too long and not ended in given duration then second conscutive thread will not start once the first task will get finsished and will not imediately get started while the first thread has comepleted their task and gievn duration has been elapsed. JVM Will decide when the next task will get executed .
I think that will help you to choose method Becuase due to this i got big problem
I can see your premiss but your conclusion is not quite right.
Here is a good and quite complete explanation according to this Tutorial for understanding the diferences bitween these two.
scheduleAtFixedRate (Runnable, long initialDelay, long period, TimeUnit timeunit)
This method schedules a task to be executed periodically. The task is executed the first time after the initialDelay, and then recurringly every time the period expires.
If any execution of the given task throws an exception, the task is no longer executed. If no exceptions are thrown, the task will continue to be executed until the ScheduledExecutorService is shut down.
If a task takes longer to execute than the period between its scheduled executions, the next execution will start after the current execution finishes. The scheduled task will not be executed by more than one thread at a time.
scheduleWithFixedDelay (Runnable, long initialDelay, long period, TimeUnit timeunit)
This method works very much like scheduleAtFixedRate() except that the period is interpreted differently.
In the scheduleAtFixedRate() method the period is interpreted as a delay between the start of the previous execution, until the start of the next execution.
In this method, however, the period is interpreted as the delay between the end of the previous execution, until the start of the next. The delay is thus between finished executions, not between the beginning of executions.
Let's write a simple program:
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
var time = 0L
var start = System.currentTimeMillis()
val executor = Executors.newScheduledThreadPool(1)
executor.scheduleWithFixedDelay({
if (time >= 12_000L) {
executor.shutdown()
} else {
Thread.sleep(2000L)
val now = System.currentTimeMillis()
time += now - start
System.out.println("Total $time delay ${now - start}\n")
start = now
}
}, 0L, 1000L, TimeUnit.MILLISECONDS)
And see the results:
| scheduleWithFixedDelay | scheduleAtFixedRate |
|:----------------------:|:----------------------:|
| Total 2001 delay 2001 | Total 2003 delay 2003 |
| Total 5002 delay 3001 | Total 4004 delay 2001 |
| Total 8003 delay 3001 | Total 6004 delay 2000 |
| Total 11003 delay 3000 | Total 8004 delay 2000 |
| Total 14003 delay 3000 | Total 10005 delay 2001 |
| --- | Total 12005 delay 2000 |
NOTICE the execution time is bigger than waiting
scheduleWithFixedDelay keeps delay
scheduleAtFixedRate removes delay
scheduledExecutorService.scheduleAtFixedRate(() -> {
System.out.println("runnable start"); try { Thread.sleep(5000); System.out.println("runnable end");} catch
(InterruptedException e) { // TODO Auto-generated catch block
e.printStackTrace(); }}, 2, 7, TimeUnit.SECONDS);
scheduledExecutorService.scheduleWithFixedDelay(() -> {
System.out.println("runnable start"); try { Thread.sleep(5000); System.out.println("runnable end");} catch
(InterruptedException e) { // TODO Auto-generated catch block
e.printStackTrace(); } }, 2, 7, TimeUnit.SECONDS);
Just execute it, and you will know the difference. Thank you

Load Test using Java - timer task vs scheduler

I need to execute a load test using Java in which one of the test strategies require x threads to be fired of every y period of time for z minutes and thereafter have a constant totalThread amount of threads running for the load test duration (eg with a total of 100 threads, start 10 threads at 5 second intervals until all 100 threads have started, and continue to keep all 100 threading running (once it has finished execution it should restart) for the specified duration of the test, say one hour)
I have attempted to use the timer task but it seems limiting, would thread pool scheduler be a better option? What would be the best approach?
public class MyTask extends TimerTask{
public void run() {
System.out.println("STARTING THREAD "+ counter +" "+ new Date());
//execute test
counter++;
if (counter > maxIterations) {
MyTask.this.cancel();
return;
}
}
List<TimerTask> MyTaskList = new ArrayList<TimerTask>();
for (int i = 1 ; i <= threadsPerIteration ; i++) {
TimerTask MyTimerTask = new MyTask(NumberOfIterations);
MyTaskList.add(MyTimerTask);
timer.schedule(MyTimerTask, initialDelayMilli, threadDelayMilli);
}
Thank You
Don't use a TimerTask for each thread. Instead, use a single TimerTask, that fires once per interval, with your example numbers once every 5 seconds.
Each of the first 10 times the TimerTask fires, it spawns off 10 threads. On each subsequent firing, it checks for the number of active threads, and spawns off enough new threads to bring the total to 100, until the end of your test.
Thanks for the help, i decided to use the threadpool executor together with the timertask class as follows:
I used the Executors.newScheduledThreadPool(int x) method to control the amount of threads able to run concurrently, together with a timer task that is set to increase the threadpool size every y amount of time :
TimerTask DelayTimerTask = new TimerTask() { //task to increase threadpool size
public void run() {
MyExecutor.setCorePoolSize(i * incrementAmount); //timer task increments threadpool size by threadPoolIncrement
i++;
}
};
timer.scheduleAtFixedRate(DelayTimerTask,0,intervalLength);
in this way the amount of concurrent threads will increase by incrementAmount every intervalLength.

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

Java execute method from within a loop every few seconds

I have a Thread that runs in my test app with a while loop inside the thread. While the while loop is running i want to execute a method from within this while loop every 30 seconds. Inside the while loop, don't want to sleep the thread or stop the loop, it must run and every 30 seconds call the method.
Thread myThread = new Thread() {
#Override
public void run() {
//my code that runs with a loop
//while loop here that runs and needs to execute method every 30 seconds, if condition met continue else break;
};
myThread.start();
}
To wait, you can use
Thread.sleep(milliseconds);
For documentation, see here
If you wait for 30 seconds in your loop, it happens every 30 seconds + execution time of your function. As long as your function call only takes milliseconds this is as precise as doing it in a more complex way.
If you want your loop to keep running but you do not want to launch a new Thread, you can use the current Time:
long lastCall = 0;
while(bla) {
if(System.currentTimeMillis() - lastCall > 30000) {
lastCall = System.currentTimeMillis();
callTheFunction();
}
}
Place it where thread is executed:
Thread.sleep(30000);

What is the difference between schedule and scheduleAtFixedRate?

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.

Categories

Resources