1

I have list of Processes and i want to execute them like, Ten processes per minute.

I tried ExecutorService, ThreadPoolExecutor, RateLimiter but none of them can support my case, also i tried RxJava but maybe i cannot figure out how ti implement it correctly.


Example

I have list of Runnable with size 100K, each Runnable have this logic:

  • Retrieve data from rest api.
  • Do some calculation on data.
  • Save the result in database.

So i used ExecutorService with size 10 and make Delay(5 seconds) inside Runnable#run() to manage what i need "Ten processes per minute", but still, it's not manageable.

The main point of this logic to decrease requests on rest api.


UPDATE

effectively what we're looking for is to have an upper limit (in time and count of operations) rather than evenly distribute the time across operations regardless of their individual throughput.

i.e. if I have a list of 100 ops which will take 0.5 seconds each, and I have a rate limiter than (after distribution) determined that a single operation should take 0.8 seconds I then have a gap of 0.3 second I can use to start a new operation

Mohamd Ali
  • 2,146
  • 4
  • 23
  • 30
  • 1
    what does exactly ten processes per minute means? – Federico Ciuffardi Feb 20 '19 at 15:02
  • I update my question. – Mohamd Ali Feb 20 '19 at 15:50
  • Can you share your code (in a simple example) ? – Brian Agnew Feb 20 '19 at 15:53
  • I'm interested, how does RateLimiter not solve this? `RateLimiter.create((double) 10 / (double) 60)` does that not achieve what you want? Do you not need the even distribution of runnables? – John Vint Feb 20 '19 at 16:48
  • effectively what we're looking for is to have an upper limit (in time and count of operations) rather than evenly distribute the time across operations regardless of their individual throughput. i.e. if I have a list of 100 ops which will take 0.5 seconds each, and I have a rate limiter than (after distribution) determined that a single operation should take 0.8 seconds I then have a gap of 0.3 second I can use to start a new operation. – Mohamd Ali Feb 27 '19 at 13:28

3 Answers3

0

I would probably feed my threadPool from a DelayQueue to limit yourself to 10 per minute.

See https://stackoverflow.com/a/6306244/823393 for an example of how to feed an executor from a BlockingQueue.

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
0

You mean like this? A single executor which spawns a thread which itself spawns 10 threads.

private static final int numProcesses = 10;
private static final ExecutorService executorService = Executors.newFixedThreadPool(numProcesses);

public static void main(String[] args)
{
    final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    executorService.scheduleAtFixedRate(Test::spawnTenThreads, 0, 5, TimeUnit.SECONDS);
}

private static void spawnTenThreads()
{
    for (int i = 0; i < numProcesses; ++i)
    {
        final int iteration = i;
        executorService.submit(() -> System.out.println(iteration));
    }
}
Michael
  • 41,989
  • 11
  • 82
  • 128
0

I think you will get the best results using a java.util.Timer and schedule a TimerTask at a fixed rate.

Let's say you have a TimerTask that prints out the date when executed.

public class PrintTimeAndIdTask extends TimerTask {

    private int id;

    public PrintTimeAndIdTask(int id) {
        this.id = id;
    }

    public void run() {
        System.out.println(new Date() + " : " + id);
    }
}

then create a timer and schedule the tasks. Each with a different delay so that they are equally distributed within your preferred time interval.

public static void main(String[] args) {
    Timer timer = new Timer();

    int taskCount = 10;
    int timeIntervalMs = 60000;
    int delayBetweenTasks = timeIntervalMs / taskCount;


    for (int i = 0; i < taskCount; i++) {
        TimerTask timerTask = new PrintTimeAndIdTask(taskCount);

        int taskDelay = (long) taskCount * delayBetweenTasks;

        timer.scheduleAtFixedRate(timerTask, taskDelay, timeIntervalMs);
    }
}

and you will see that every 6 seconds a task gets executed.

Wed Feb 20 17:17:37 CET 2019 : 0
Wed Feb 20 17:17:43 CET 2019 : 1
Wed Feb 20 17:17:49 CET 2019 : 2
Wed Feb 20 17:17:55 CET 2019 : 3
Wed Feb 20 17:18:01 CET 2019 : 4
Wed Feb 20 17:18:07 CET 2019 : 5
Wed Feb 20 17:18:13 CET 2019 : 6
Wed Feb 20 17:18:19 CET 2019 : 7
Wed Feb 20 17:18:25 CET 2019 : 8
Wed Feb 20 17:18:31 CET 2019 : 9
Wed Feb 20 17:18:37 CET 2019 : 0
Wed Feb 20 17:18:43 CET 2019 : 1
Wed Feb 20 17:18:49 CET 2019 : 2
Wed Feb 20 17:18:55 CET 2019 : 3
....

Keep in mind that a Timer does not run as a daemon thread by default. If you don't cancel it explicitly on application shutdown it keeps runnig and thus your application will not shutdown.

René Link
  • 48,224
  • 13
  • 108
  • 140