neptune692
neptune692

Reputation: 353

Java ScheduledThreadPoolExecutor running 15 milliseconds late / inconsistent time?

I'm new too this site so forgive me if I've posted this questions in the wrong place or something :)

I've been researching and creating test programs non-stop trying to figure out what might be going wrong with the ScheduledThreadPoolExecutor I create.

The Problem:

When running the below test application the ScheduledThreadPoolExecutor scheduled to run at a fixed rate of 3 milliseconds runs chaotically with frequent spikes of greater than 15 milliseconds. It should execute at a rate of every 3 milliseconds.

Interesting Details:

The problem only occurs outside of the IDE, the ScheduledThreadPoolExecutor runs as expected inside an IDE such as Netbeans or IntelliJ.

Question:

Why am I getting very inconsistent times using the Timer and ScheduledThreadPoolExecutor classes? The time between executions range from the expected 3 milliseconds per execution to frequent spikes of 15 milliseconds between execution.

Configuration:

Java 7 Update 5, IntelliJ IDE, Windows 7, Run from Command Prompt.

Test App Demonstrating the Problem, make sure to use outside of an IDE to see the problem. This program will output times that are greater then the expected time between execution. Should be around 15 milliseconds instead of the expected 3.

Thank you all for your help! :)

package testtime;

import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestTime extends JFrame {

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestTime().setVisible(true);
            }
        });
    }

    JTextArea area = new JTextArea();
    JScrollPane pane = new JScrollPane(area);

    ScheduledThreadPoolExecutor executor;

    public TestTime() {
        setSize(300, 300);
        setAlwaysOnTop(true);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        area.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                area.setText("--Press anywhere to start--\n\n" +
                        "If time exceeds 3 milliseconds it will be printed here...\n\n" +
                        "------------------------------------\n\n");
                executor = new ScheduledThreadPoolExecutor(1);
                executor.scheduleAtFixedRate(new Loop(), 0L, 3L, TimeUnit.MILLISECONDS);
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                executor.shutdownNow();
            }
        });

        area.setLineWrap(true);
        area.setWrapStyleWord(true);
        area.setText("--Press anywhere to start--");
        add(pane);
    }

    class Loop extends Thread {
        long time = 0L;

        @Override
        public void run() {
            long timeTaken = System.nanoTime() - time;
            time = System.nanoTime();

            if(timeTaken > 3500000L) {
                area.append(timeTaken+"(nanoseconds)  -- "+(timeTaken/1000000L)+"(milliseconds)\n");
            }
        }
    }
}

Upvotes: 4

Views: 1161

Answers (3)

Tim Bender
Tim Bender

Reputation: 20442

Technically, the contract specified by the Timer and ScheduledExecutor interfaces do not guarantee that the tasks will execute exactly at the interval specified. They simply promise not to run them any sooner than the interval.

Upvotes: 1

Marc
Marc

Reputation: 1976

I think the Windows timer simply doesn't have such a fine resolution. You find more on that topic if you Google http://www.google.de/search?q=windows+timer+resolution

Upvotes: 1

Laurent Perrin
Laurent Perrin

Reputation: 14881

I think that your problem comes from the garbage collector, which periodically freezes the process to remove unused objects from memory.

The JVM supports several different GC algorithms. There is a tradeoff between latency and throughput.

It's possible that IntelliJ uses a low pause GC to favor UI quick response, while the JVM defaults to high throughput outside of the IDE.

Can you try adding the -Xincgc option (to select Concurrent Mark&Sweep) to your project ?

Upvotes: 3

Related Questions