简体   繁体   中英

Java ExecutorService, setting an overall fixed rate for all work in a queue

Given the below code:

ScheduledExecutorService es = new ScheduledThreadPoolExecutor(100);

es.scheduleAtFixedRate(() -> {
        System.out.println("Do work with a fixed rate! ");
}, 0, 1000, TimeUnit.MILLISECONDS);


int i = 0;
while ( i < 100 ) {
        es.scheduleAtFixedRate(() -> {
                System.out.println("Do more work with a fixed rate! Doesn't really work! We will end up with 100 'workers', each running with a fixed rate! ");
        }, 0, 1000, TimeUnit.MILLISECONDS);

        i++;
}

which creates a SchedueledThreadPoolExecutor .

In the while loop, we are simulating someone else wanting to add more work to the queue, but this won't obviously work.

I am guessing, that one needs to implement some sort of ThreadPoolExecutor which uses a Queue of some sort, possibly a delayed queue.

The idea is that the executor is created and then it has a fixed rate at which it can execute tasks. If a task finishes too quickly threads that have finished need to wait to do pull off more work.

If one finishes too slowly, then the global time should allow other threads in the threadpool to pull off more work.

http://docs.oracle.com/javase/7/docs/api/java/util/AbstractQueue.html

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/DelayQueue.html

But I was hoping this was already done, as it should be pretty common problem.

Does anyone have a good solution to this?

It is not entirely clear what you want to do, but my guess is that you want a kind of Pacer or Throttler that ensures that tasks are executed with a certain rate (think of the revolving doors found at entrances to office buildings and others, the speed of the door determines the number of persons that can enter (or exit) the building per time unit and the time difference between each entrance (or exit)).

ScheduledExecutorServcice is not a solution for that problem. Instead, start by studying the Leaky Bucket Algorithm .

A ScheduledThreadPoolExecutor maintains a queue of tasks that is ordered by the tasks' next scheduled execution. These tasks (the Runnable instances you provide) are completely independent of the threads that will execute them. In other words, the threads don't just acquire a task, execute it, then go to sleep waiting for that task's next execution.

Instead, the threads poll the queue, acquire a task, execute it, schedule the next execution of their task by reinserting it into the queue, then poll the queue again. If the queue has a task, great. If not, they wait until the next task is ready (whether it's currently in the queue or added at a later time). They then restart this whole process.

All this to say, that a ScheduledThreadPoolExecutor with 100 threads can easily process more than 100 tasks at any type of rate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM