OiO.lk Blog java Timer delay fluctuations in Java – how to improve?
java

Timer delay fluctuations in Java – how to improve?


I am trying to put together a timer class for a game. Until now, I was just using javax.swing.Timer, but after trying to do some operations that require more exact timing (specifically visual interpolation between two ticks’ states when rendering more frames than there are ticks), I found this class’s limitations and it proved unusable.

I tried to put together my own timer, going off available functions and just how I intuitively imagined a timer could work like this. It seems to give better results, yet there are still weird fluctuations, some of which don’t make sense with the code written (image with stats). Like, how could the delay ever be smaller than 5? The condition for the function firing is the delayed timestamp being reached. Could this be some weird race condition?
logged time delays, printed by the runFunc() function run threaded

This is the entire test class for this (just deleted package line).

public class TimerTest {
    // for debug
    public double averageTimeMillis;
    int timesLogged;
    // Timer vars
    long lastTickTimeMillis;
    long lastTickTimeNano;
    long nextTimestampNano;
    long delayNano;

    public TimerTest(long delayNano) {
        timesLogged = 0;
        averageTimeMillis = delayNano;

        lastTickTimeMillis = System.currentTimeMillis();
        lastTickTimeNano = System.nanoTime();

        this.delayNano = delayNano;
        nextTimestampNano = lastTickTimeNano+delayNano;

        new Thread(this::run).start();
    }

    private void run() {
        for (;;) {update();}
    }

    private void update() {
        long timeNowNano = System.nanoTime();
        if (timeNowNano>nextTimestampNano) {
            // Run, or threaded*
            new Thread(this::runFunc).start();
//            runFunc();
            nextTimestampNano+=delayNano;
        }
    }

    private void runFunc() {
        long timeNowMillis = System.currentTimeMillis();
        long timeNowNano = System.nanoTime();

        long millisDelay = timeNowMillis - lastTickTimeMillis;
        long nanoDelay = timeNowNano - lastTickTimeNano;

        averageTimeMillis = (averageTimeMillis*timesLogged+millisDelay)/(timesLogged+1);
        timesLogged++;

        System.out.println(millisDelay + " | " + nanoDelay + " | " + averageTimeMillis);

        lastTickTimeMillis = timeNowMillis;
        lastTickTimeNano = timeNowNano;
    }

    public static void main(String[] args) {
        new TimerTest(5000000); // 5 ms delay, just for testing, in game will be higher
        for (;;) {} // to let timer run
    }
}

Another weird observation is that after the "//Run, or threaded*" comment, running the function normally seems to give significantly lower fluctuations than running it threaded. The reason I threaded it is that I don’t want the run of the function to slow down the timer, were it to run longer than the delay. But now that I think about how two instances of runFunc() changing the same state simultaneously would work, no threading might be the right approach. It does still however produce fluctuations commonly. fluctuations with runFunc() not on a new thread

Anyone with experience with this in Java have any tips on why the fluctuations might happen, and how to fix it?

I tried debugging, however the specifics of the task make that difficult, and I didn’t get any good results.

I tried increasing the delay, which realistically it will be used with a delay of at least 10-20 ms, and it does seem to minify the fluctuations, but only because they don’t seem to scale with the delay, so they have a smaller impact on bigger numbers. Their frequency doesn’t seem to be impacted (from a glance).



You need to sign in to view this answers

Exit mobile version