Each Timer uses only one thread to service its tasks. The timer thread will run your task until it finishes, and only then try to schedule its next execution. The documentation for Timer confirms this problem and warns its users that tasks are "grouped."
After completing your task, the manager Timer will then try to schedule it again. The next scheduled execution is likely to be in the past, according to the allocation policy Timer$TimerThread#mainLoop() : adds the task period to the last scheduled task execution time. Since in your case the planned execution time will be more than three seconds in the past, adding three seconds to it still gives the next planned execution time in the past.
It's good; the algorithm allows such slippage. Your task will be launched immediately after the last launch. What you do not receive is your desire once every three seconds. Instead, you will receive as often as possible, but not more often than every three seconds.
source share