This is a follow up on my thread "Util library to help make my code run *slower*?". After using ScheduledExecutorService.scheduleAtFixedRate for a while now I noticed that it was not as good as I first thought. What I want to do is to schedule X number of concurrent threads to run in an evenly distributed fashion. Lets say I want them to execute at most 10 times per second. So if I have 10 threads I want them to execute at the following times counted in milliseconds from the start:
0, 100, 200, 300, 400, 500 etc..
I thought I would accomplice this by setting the delay of the first schedule to 0 ms, the second one to 100 ms etc, and using 1000 ms as a period for all. But that didn't work at all. All the threads gets executed in a bunch on every second, almost exactly.
This is the code:
My TestRunner class simply prints some time information, like the time since the last run, and that number is very low (mostly 0ms, but once in a while maybe 15ms) but then every second it goes up to about 1000ms. Ie it is triggered in bursts rather then in the distributed fashion I expected.
Also, the TestRunner finishes by sleeping for 50ms, simulating doing some real work. But that should not effect the scheduler since it is on a fixed rate lower then 1000ms.
As a side note I first tried using only a single schedule, with a period of 100ms, but the second I started increasing the sleeptime in TestRunner above 100ms it started to effect the time in between runs. And when I increased the sleep time to 1000 ms with the code above it meant that the thread ran once every second. And that is of course what is expected, if one reads the documentation for scheduleAtFixedRate.
So then I tried the method scheduleWithFixedDelay, with this code:
That works great, as long as the sleep time in TestRunner is constant and not to large. When the sleep time comes close to constant 1000ms I notice occasional trigger bursts, but otherwise they trigger happened in about 90 and 110 ms intervalls. And the higher the sleep time I choose, the bursts occurs more frequently, but that is expected, and in reallity I will never expect that the execution time for a single "task" is this high each time. However, the execution time might vary, so to simulate that I made the TestRunner sleep a random time between 50 and 500ms. And when I started the test it indicated good numbers at first, but after having run for about 5 seconds the numbers become all screwed up. Sometimes the time between two runs is 0ms, and sometimes it is almost 600ms. The average is still good, but I want them distributed more evenly.
So then I figured I should try using the scheduleAtFixedRate-method again, and using the same code as above it gave me perfect numbers as long as the sleep time was under 1000ms. But when I let the random sleep time be between 50 and 1500ms then it didn't take long until I saw the same extreme numbers, just as before. It seems that the schedule has been "shaken" by this occational long execution time, and that it can't "recover". And as before, the average is good (close to perfect, even), but I want them distributed more evenly. I don't want anything lower then lets say 80ms between two triggers, while still maintaining a good average. A very few extreme exceptions (maybe once out of a 100) can of course be allowed, but not as many as I am seeing now (only about 25% is within 90ms-110ms).
Basically, what I want is to have a single schedule with fixed delay, but that is executed over more then one thread.
Can anyone give some tips on how I can acchieve this? I'm not looking for perfect numbers, or real time scheduling. I'm just looking for a "good enough" solution where X number of tasks execute concurrently in a somewhat evenly distributed pattern, with Y number of executions per second and where each execution can take between lets say 10ms and 2000ms but most likely in the 200-700ms range, and it should be able to maintain this even distribution for a longer period of time.
Joined: May 19, 2001
I just noticed that by increasing the schedule count and the thread pool size to 20 I got *much* better numbers. Now they are practically perfect. But is that what it takes? Using a lot of threads? And some simple tests incidates that the longer the execution time can be, the more schedules and threads are needed. Seems like there must be a more optimal solution.