3

Details: For a lot the programs that I develop I use this code (or some slight variant) to "tick" a method every so often, set to the varaible tps (if set to 32 it calls the method tick 32 times every second). Its very essential so I can't remove it from my code as animations and various other parts will break.

Unfortunately it seems to use a sizable amount of cpu usage for a reason I can't figure out. A while back I was thinking about using thread.sleep() to fix this issue but according to this post; it's rather innacurate which makes it unfeasible as this requires reasonably accurate timing.

It doesn't use that much cpu, around 6-11% cpu for a ryzen 1700 in my admittedly short testing, but it's still quite a lot considering how little it's doing. Is there a less cpu intensive method of completing this? Or will the timing be to innacurate for regular usage.

public class ThreadTest {

    public ThreadTest() {
        int tps = 32;

        boolean threadShouldRun = true;
        long lastTime = System.nanoTime();
        double ns = 1000000000 / tps;
        double delta = 0;
        long now;

        while (threadShouldRun) {
            now = System.nanoTime();

            delta += (now - lastTime) / ns;
            lastTime = now;

            while ((delta >= 1) && (threadShouldRun)) {
                tick();
                delta--;
            }
        }
    }

    public void tick() {

    }

    public static void main(String[] args) {
        new ThreadTest();
    }
}

Basic summary: The code above uses 6-11% cpu with a ryzen 1700, is there a way in java to accomplish the same code with less cpu usage and keeping reasonable timing when executing code a certain amount of times per second.

  • How many time tick method is executing (can you add a counter and print it?) When are you updating threadShouldRun? My suggestion is to print nanoseconds after each statement and see where the delay is. – Amit Mahajan Jan 24 '18 at 00:10
  • 8
    Because the thread is constantly running with no sleep or voluntary yield. While the intention is to provide a hight level of precision, it will tend to run the thread hot (and continuously consume CPU cycles) – MadProgrammer Jan 24 '18 at 00:10
  • A single-threaded infinite loop consumes one core, what more/less could you want ? ;) – javaPhobic Jan 24 '18 at 00:21
  • The threadShouldRun method is for stopping the program, so it doesnt run indefinitely, normaly it will change, but in the short code I made for the question it doesnt. –  Jan 24 '18 at 00:44
  • 1
    This is a solved problem and you should consider using a scheduling service as suggested. But even without doing that, you'll probably notice some improvement with minimal risk of inaccuracy simply by adding `Thread.yield()` in your tight loop. – Paul Hicks Jan 24 '18 at 00:47
  • 2
    @PaulHicks With Java 9, you can now use `Thread.onSpinWait();` as well. – Jacob G. Jan 24 '18 at 01:08
  • Cool, didn't know about that. Seems like `onSpinWait()` is specifically for cases where something else needs to happen, so in this case, `yield()` might be the more self-documenting option. – Paul Hicks Jan 24 '18 at 02:00

1 Answers1

4

One easy alternative that shouldn't use as much CPU is to use a ScheduledExecutorService. For example:

public static void main(String[] args) {
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

    executor.scheduleAtFixedRate(() -> {

    }, 0, 31250, TimeUnit.MICROSECONDS);
}

Note that 31250 represents the value of 1/32 seconds converted to microseconds, as that parameter accepts a long.

Jacob G.
  • 28,856
  • 5
  • 62
  • 116