java.util.concurrent.ScheduledExecutorService.scheduleAtFixedRate invokes thread every 4-5 seconds when configured for 12 hours

Viewed 98

I have a singleton class that creates a thread on instance creation. Only one object of this class is created and the thread is scheduled to run every 12 hours and print the given statement. In some cases after the first 12h the thread is invoked every 4-5 seconds. I am confused as to why this happens as I have configured the scheduler to run once every 12 hours and not every 4-5 seconds. Is there any config I have missed or is the scheduler wrong configured?

the singleton class,

import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

public class ThreadSchedulerTest {
private static final ThreadSchedulerTest test = new ThreadSchedulerTest();
private ThreadSchedulerTest (){createThread();}

private void createThread() {

        Runnable renewer = () -> {
            System.out.println("Running ok , time is : "+ Instant.now());
        };
        Executors.newSingleThreadScheduledExecutor(new 
 ThreadSchedulerThreadFactory("thread1")).scheduleAtFixedRate(
                renewer, 0, 12, TimeUnit.HOURS);

}
static class ThreadSchedulerThreadFactory implements ThreadFactory {
    private final String name;

    public ThreadSchedulerThreadFactory(final String name) {
        this.name = name;
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r, name);
        thread.setDaemon(true);
        return thread;
    }
}
}

Can someone please help clarify this issue?

1 Answers

You will find it easier to test the if you change the TimeUnit to SECONDS and make the Runnable print hashcode of the instance:

Runnable renewer = () -> {
    System.out.println("Running ok instance="+ThreadSchedulerTest.this.hashCode()+", time is : "+ Instant.now());
};

Your problem with repeating every 4-5 seconds is probably that you have created two instances of ThreadSchedulerTest. The above message fix will confirm.

The code you have provided will not run as you have recursive definition of the constructor and member variable. Thus every instance of ThreadSchedulerTest executes second constructor ThreadSchedulerTest test = new ThreadSchedulerTest(); - which then instantiates a new member test:

new ThreadSchedulerTest()
|  Exception java.lang.StackOverflowError
|        at ThreadSchedulerTest.<init> (#5:2)

You can fix my making this declaration - test is static and constructor private so only one instance is ever constructed:

public class ThreadSchedulerTest {
   static final ThreadSchedulerTest test = new ThreadSchedulerTest();
   private ThreadSchedulerTest () {
        createThread(); 
   }
   ...
Related