Обслуживание Исполнителя и Ограничитель Скорости - PullRequest
2 голосов
/ 20 апреля 2019

У меня есть класс, который вызывает сторонний API. Сейчас я работаю над реализацией, при которой к стороннему API должно быть отправлено только 10 запросов.

Я подумал об использовании службы executor с фиксированным пулом потоков, как показано ниже.

public class SimpleRateLimiter {

    private ExecutorService executorService = Executors.newFixedThreadPool(10);
    private static SimpleRateLimiter srl = new SimpleRateLimiter();

    private SimpleRateLimiter() {}

    public static SimpleRateLimiter getInstance() {
        return srl;
    }

    public void doSomething() {
        executorService.submit(new Runnable() {         
            @Override
            public void run() {

                // call to 3rd party api
            }
        });
    }

    public void terminate() throws Exception {
        executorService.shutdown();
    }

}

Насколько я понимаю, , поскольку в пуле у меня только 10 рабочих потоков, поэтому в любое время к стороннему API можно сделать только 10 запросов с использованием приведенного выше кода. Но это не значит, что служба Executor отклонит все остальные запросы. Скорее, он примет все запросы и назначит запрос рабочему потоку после завершения выполнения задачи, над которой работал.

Верно ли вышеизложенное понимание?

Ответы [ 2 ]

2 голосов
/ 20 апреля 2019

Да, ваше понимание верно, если вы посмотрите на реализацию Executors.newFixedThreadPool(), она возвращает экземпляр ThreadPoolExecutor с неограниченным BlockingQueue реализацией:

 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
 }

LinkedBlockingQueue - необязательно ограниченная реализация BlockingQueue, в которой вы можете игнорировать аргумент емкости своего конструктора, если вы ничего не указали, максимальный размер очереди равен Integer.MAX_VALUE:

public LinkedBlockingQueue() {
       this(Integer.MAX_VALUE);
}

Таким образом, в отношении вашего вопроса все задачи будут отправлены в пул потоков , и одновременно будут выполняться только 10 потоков, которые будут вызывать API, а остальные будут поставлены в очередь.

В отличие от этого, если вы используете пользовательский ThreadPoolExecutor с ограниченной реализацией BlockingQueue, такой как ArrayBlockingQueue (с предопределенной емкостью), вместо LinkedBlockingQueue в том случае, если все потоки заняты, а очередь заполнена и вы пытаетесь отправить другую задачу, задача будет отклонена .

В вашем коде executorService.submit будет продолжать принимать новые задачи (до Integer.MAX_VALUE задач), но только 10 потоков будут работать в данный момент времени.

0 голосов
/ 20 апреля 2019

Полагаю, было бы проще использовать библиотеку [guava] (https://google.github.io/guava/releases/19.0/api/docs/index.html?com/google/common/util/concurrent/RateLimiter.html) для своей работы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...