Поделиться через


ThreadPoolExecutor Класс

Определение

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

[Android.Runtime.Register("java/util/concurrent/ThreadPoolExecutor", DoNotGenerateAcw=true)]
public class ThreadPoolExecutor : Java.Util.Concurrent.AbstractExecutorService
[<Android.Runtime.Register("java/util/concurrent/ThreadPoolExecutor", DoNotGenerateAcw=true)>]
type ThreadPoolExecutor = class
    inherit AbstractExecutorService
Наследование
Производный
Атрибуты

Комментарии

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

Пулы потоков устраняют две разные проблемы: обычно они обеспечивают повышенную производительность при выполнении большого количества асинхронных задач, из-за снижения затрат на вызов задач, а также обеспечивают возможность привязки ресурсов и управления ими, включая потоки, потребляемые при выполнении коллекции задач. Каждый из них ThreadPoolExecutor также поддерживает некоторые основные статистические данные, такие как количество завершенных задач.

Чтобы быть полезным в широком диапазоне контекстов, этот класс предоставляет множество настраиваемых параметров и перехватчиков расширяемости. Однако программисты настоятельно призывают использовать более удобные Executors методы Executors#newCachedThreadPool фабрики (несогласованный пул потоков с автоматическим восстановлением потока), Executors#newFixedThreadPool (пул потоков фиксированного размера) и Executors#newSingleThreadExecutor (один фоновый поток), которые предварительно настраивают параметры для наиболее распространенных сценариев использования. В противном случае используйте следующее руководство при настройке и настройке этого класса вручную.

<dl>

<dt>Core и максимальный размер пула</dt>

<dd>A ThreadPoolExecutor автоматически настраивает размер пула (см#getPoolSize. ) в соответствии с границами, заданными corePoolSize (см#getCorePoolSize. ) и maximumPoolSize (см. ).#getMaximumPoolSize

При отправке новой задачи в методе #execute(Runnable), если выполняется меньше, чем потоки corePoolSize, создается новый поток для обработки запроса, даже если другие рабочие потоки неактивны. Кроме того, если выполняется меньше, чем максимальное число потоковPoolSize, создается новый поток для обработки запроса только в том случае, если очередь заполнена. Задав corePoolSize и maximumPoolSize то же самое, создайте пул потоков фиксированного размера. Задав максимальное значениеPoolSize, например, неограниченное значение, например Integer.MAX_VALUE, позволяет пулу размещать произвольное количество параллельных задач. Как правило, размеры ядра и максимального размера пула задаются только при построении, но они также могут быть динамически изменены с помощью #setCorePoolSize и #setMaximumPoolSize. </dd>

<dt>По запросу строительство</dt>

<>По умолчанию даже основные потоки изначально создаются и запускаются только при поступлении новых задач, но это может быть переопределено динамически с помощью метода #prestartCoreThread или #prestartAllCoreThreads. Возможно, вы хотите предварительно начать потоки, если вы создаете пул с непустой очередью. </dd>

<dt>Создание новых потоков</dt>

<Новые потоки dd>создаются с помощью .ThreadFactory Если не указано иное, используется объект Executors#defaultThreadFactory , который создает потоки для всех в одном и том же ThreadGroupNORM_PRIORITY приоритете и состоянии, отличном от управляющей программы. Указав другой ThreadFactory, вы можете изменить имя потока, группу потоков, приоритет, состояние управляющей программы и т. д. ThreadFactory Если не удается создать поток при запросе, возвращая значение NULL newThread, исполнитель продолжит работу, но не сможет выполнять какие-либо задачи. Потоки должны иметь значение "modifyThread". RuntimePermission Если рабочие потоки или другие потоки, использующие пул, не имеют этого разрешения, служба может быть понижена: изменения конфигурации могут не вступить в силу своевременно, и пул завершения работы может оставаться в состоянии, в котором возможно завершение, но не завершено.</dd>

<dt Keep-alive times</dt>>

<dd,>если пул в настоящее время имеет больше, чем потоки corePoolSize, избыточные потоки будут завершены, если они были бездействуют больше, чем keepAliveTime (см. ).#getKeepAliveTime(TimeUnit) Это позволяет сократить потребление ресурсов, если пул не используется. Если пул становится более активным позже, будут созданы новые потоки. Этот параметр также можно изменить динамически с помощью метода #setKeepAliveTime(long, TimeUnit). Использование значения Long.MAX_VALUETimeUnit#NANOSECONDS эффективно отключает бездействующие потоки от завершения до завершения работы. По умолчанию политика поддержания активности применяется только в том случае, если существует больше потоков corePoolSize, но метод #allowCoreThreadTimeOut(boolean) можно использовать для применения этой политики времени ожидания к основным потокам, так как значение keepAliveTime не равно нулю. </dd>

<dt Queuing</dt>>

<dd>Any BlockingQueue может использоваться для передачи и удержания отправленных задач. Использование этой очереди взаимодействует с размерами пула:

<ul>

<li>Если выполняется меньше, чем потоки corePoolSize, исполнитель всегда предпочитает добавлять новый поток, а не очередь.

<li>Если выполняется corePoolSize или больше потоков, исполнитель всегда предпочитает очередь запроса, а не добавление нового потока.

<li>Если запрос не может быть поставлен в очередь, создается новый поток, если это не превысит максимальный размерPoolSize, в этом случае задача будет отклонена.

</ul>

Существует три общие стратегии для очереди: <ol>

<li><em> Direct handoffs.</em> Хороший выбор по умолчанию для рабочей очереди — это SynchronousQueue то, что выполняет задачи в потоки, не удерживая их в противном случае. Здесь попытка очереди задачи завершится ошибкой, если потоки не доступны для его запуска, поэтому будет создан новый поток. Эта политика позволяет избежать блокировки при обработке наборов запросов, которые могут иметь внутренние зависимости. Прямые передачи обычно требуют несвязанных максимальных значенийPoolSizes, чтобы избежать отказа от новых отправленных задач. Это, в свою очередь, признает возможность несвязанного роста потока, когда команды продолжают поступать в среднем быстрее, чем они могут быть обработаны.

<li><em> Unbounded queues.</em> С помощью несвязанной очереди (например, LinkedBlockingQueue без предопределенной емкости) новые задачи будут ждать в очереди, когда все потоки corePoolSize заняты. Таким образом, никогда не будут создаваться потоки corePoolSize. (Поэтому значение maximumPoolSize не имеет никакого эффекта.) Это может быть уместно, если каждая задача полностью не зависит от других, поэтому задачи не могут повлиять на выполнение друг друга; например, на сервере веб-страницы. Хотя этот стиль очереди может быть полезен при сглаживания временных всплесков запросов, он признает возможность несвязанного роста рабочей очереди, когда команды продолжают поступать в среднем быстрее, чем они могут обрабатываться.

<li><em>Bounded queues.</em> Ограничивающая очередь (например, а ArrayBlockingQueue) помогает предотвратить исчерпание ресурсов при использовании с конечным максимальным значениемPoolSizes, но может быть сложнее настраивать и контролировать. Размеры очередей и максимальные размеры пула могут быть освобождены друг от друга: использование больших очередей и небольших пулов сводит к минимуму использование ЦП, ресурсы ОС и переключение контекста, но может привести к искусственно низкой пропускной способности. Если задачи часто блокируются (например, если они привязаны к ввода-выводам), система может запланировать время для дополнительных потоков, чем в противном случае. Использование небольших очередей обычно требует больших размеров пула, что обеспечивает более шиные ЦП, но может столкнуться с неприемлемыми затратами на планирование, что также снижает пропускную способность.

</Пр>

</dd>

<dt Отклоненные задачи</dt>>

<dd>Новые задачи, отправленные в методе#execute(Runnable), будут <отклонены< или em>> при завершении работы исполнителя, а также когда исполнитель использует конечные границы для максимальной емкости потоков и рабочей очереди, а также насыщенный. В любом случае execute метод вызывает RejectedExecutionHandler#rejectedExecution(Runnable, ThreadPoolExecutor) метод его RejectedExecutionHandler. Предоставляются четыре предопределенные политики обработчика:

<Пр>

<li>По умолчанию ThreadPoolExecutor.AbortPolicyобработчик создает среду выполнения RejectedExecutionException при отклонении.

<li>, ThreadPoolExecutor.CallerRunsPolicyпоток, вызывающий execute себя, запускает задачу. Это обеспечивает простой механизм управления обратной связью, который замедлит скорость отправки новых задач.

<li>, ThreadPoolExecutor.DiscardPolicyзадача, которая не может быть выполнена, просто удаляется. Эта политика предназначена только для тех редких случаев, когда выполнение задачи никогда не зависит.

<Li>In ThreadPoolExecutor.DiscardOldestPolicy, если исполнитель не завершает работу, задача в голове рабочей очереди удаляется, а затем выполняется повторное выполнение (что может завершиться ошибкой, что приводит к повторному повторению). Эта политика редко допускается. В почти всех случаях необходимо также отменить задачу, чтобы вызвать исключение в любом компоненте, ожидающего его завершения, и /или регистрировать сбой, как показано в ThreadPoolExecutor.DiscardOldestPolicy документации.

</Пр>

Можно определить и использовать другие виды RejectedExecutionHandler классов. Для этого требуется некоторая осторожность, особенно если политики предназначены для работы только в рамках конкретных политик емкости или очередей. </dd>

<методы< dt Hook/dt>>

<Dd>Этот класс предоставляет protected переопределение #beforeExecute(Thread, Runnable) и #afterExecute(Runnable, Throwable) методы, которые вызываются до и после выполнения каждой задачи. Их можно использовать для управления средой выполнения; например, повторно инициализация ThreadLocals, сбор статистики или добавление записей журнала. Кроме того, метод #terminated можно переопределить для выполнения любой специальной обработки, которая должна выполняться после полного завершения исполнителя.

Если методы перехватчика, обратного вызова или БлокировкиQueue вызывают исключения, внутренние рабочие потоки могут в свою очередь завершиться ошибкой, резко завершить работу и, возможно, заменить их.</dd>

<обслуживание< очереди dt/dt>>

<Метод #getQueue() dd>позволяет получить доступ к рабочей очереди для мониторинга и отладки. Использование этого метода для любой другой цели настоятельно не рекомендуется. Два предоставленных метода и #remove(Runnable)#purge доступны для восстановления хранилища при отмене большого количества очередных задач.</dd>

<dt Reclamation</dt>>

<Dd>A пул, который больше не ссылается в программе <em>AND</em> , не имеет оставшихся потоков, может быть удален (сборка мусора) без явного завершения работы. Вы можете настроить пул, чтобы разрешить все неиспользуемые потоки в конечном итоге умереть, задав соответствующее время поддержания активности с помощью нижней границы нулевых потоков и /или параметра #allowCoreThreadTimeOut(boolean). </dd>

</dl>

<Пример расширения b>.</b> Большинство расширений этого класса переопределяют один или несколько методов защищенного перехватчика. Например, ниже приведен подкласс, который добавляет простую функцию приостановки и возобновления:

{@code
            class PausableThreadPoolExecutor extends ThreadPoolExecutor {
              private boolean isPaused;
              private ReentrantLock pauseLock = new ReentrantLock();
              private Condition unpaused = pauseLock.newCondition();

              public PausableThreadPoolExecutor(...) { super(...); }

              protected void beforeExecute(Thread t, Runnable r) {
                super.beforeExecute(t, r);
                pauseLock.lock();
                try {
                  while (isPaused) unpaused.await();
                } catch (InterruptedException ie) {
                  t.interrupt();
                } finally {
                  pauseLock.unlock();
                }
              }

              public void pause() {
                pauseLock.lock();
                try {
                  isPaused = true;
                } finally {
                  pauseLock.unlock();
                }
              }

              public void resume() {
                pauseLock.lock();
                try {
                  isPaused = false;
                  unpaused.signalAll();
                } finally {
                  pauseLock.unlock();
                }
              }
            }}

Добавлено в версии 1.5.

Документация по Java для java.util.concurrent.ThreadPoolExecutor.

Части этой страницы — это изменения на основе работы, созданной и общей проектом с открытым исходным кодом Android и используемой в соответствии с условиями, описанными в лицензии Creative Commons 2.5 Attribution.

Конструкторы

ThreadPoolExecutor(Int32, Int32, Int64, TimeUnit, IBlockingQueue)

Создает новый ThreadPoolExecutor с заданными начальными параметрами, фабрикой потоков по умолчанию Executors#defaultThreadFactory и ThreadPoolExecutor.

ThreadPoolExecutor(Int32, Int32, Int64, TimeUnit, IBlockingQueue, IRejectedExecutionHandler)

Создает новый ThreadPoolExecutor с заданными начальными параметрами и фабрикой потоков по умолчанию Executors#defaultThreadFactory.

ThreadPoolExecutor(Int32, Int32, Int64, TimeUnit, IBlockingQueue, IThreadFactory)

Создает новый ThreadPoolExecutor с заданными начальными параметрами и ThreadPoolExecutor.

ThreadPoolExecutor(Int32, Int32, Int64, TimeUnit, IBlockingQueue, IThreadFactory, IRejectedExecutionHandler)

Создает новый ThreadPoolExecutor с заданными начальными параметрами.

ThreadPoolExecutor(IntPtr, JniHandleOwnership)

Конструктор, используемый при создании управляемых представлений объектов JNI; вызывается средой выполнения.

Свойства

ActiveCount

Возвращает приблизительное количество потоков, которые активно выполняют задачи.

Class

Возвращает класс среды выполнения этого Objectобъекта.

(Унаследовано от Object)
CompletedTaskCount

Возвращает приблизительное общее количество задач, которые завершили выполнение.

CorePoolSize

Возвращает основное число потоков. -или- Задает основное число потоков.

Handle

Дескриптор базового экземпляра Android.

(Унаследовано от Object)
IsShutdown

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

IsTerminated

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

IsTerminating

Возвращает значение true, если этот исполнитель находится в процессе завершения после #shutdown или #shutdownNow не полностью завершен.

JniIdentityHashCode

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
JniPeerMembers

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

LargestPoolSize

Возвращает наибольшее количество потоков, которые когда-либо находились в пуле.

MaximumPoolSize

Возвращает максимально допустимое количество потоков. -или- задает максимально допустимое количество потоков.

PeerReference

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
PoolSize

Возвращает текущее количество потоков в пуле.

Queue

Возвращает очередь задач, используемую этим исполнителем.

RejectedExecutionHandler

Возвращает текущий обработчик для невыполнеемых задач. -или- Задает новый обработчик для неисключаемых задач.

TaskCount

Возвращает приблизительное общее количество задач, которые когда-либо планировались для выполнения.

ThreadFactory

Возвращает фабрику потоков, используемую для создания новых потоков. —или— задает фабрику потоков, используемую для создания новых потоков.

ThresholdClass

Этот API поддерживает инфраструктуру Mono для Android и не предназначен для использования непосредственно из кода.

ThresholdType

Этот API поддерживает инфраструктуру Mono для Android и не предназначен для использования непосредственно из кода.

Методы

AfterExecute(IRunnable, Throwable)

Метод, вызываемый при завершении выполнения заданного runnable.

AllowCoreThreadTimeOut(Boolean)

Задает политику, указывающую, могут ли основные потоки истекать и завершаться, если задачи не приходят в течение времени поддержания активности, при необходимости заменяются при поступлении новых задач.

AllowsCoreThreadTimeOut()

Возвращает значение true, если этот пул позволяет основным потокам истекать и завершаться, если задачи не приходят в течение времени keepAlive, при необходимости заменяются при поступлении новых задач.

AwaitTermination(Int64, TimeUnit)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

AwaitTerminationAsync(Int64, TimeUnit)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от AbstractExecutorService)
BeforeExecute(Thread, IRunnable)

Метод, вызываемый до выполнения заданного runnable в данном потоке.

Clone()

Создает и возвращает копию этого объекта.

(Унаследовано от Object)
Dispose()

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
Dispose(Boolean)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
Equals(Object)

Указывает, равен ли другой объект этому объекту.

(Унаследовано от Object)
Execute(IRunnable)

Выполняет заданную задачу в будущем.

GetHashCode()

Возвращает значение хэш-кода для объекта.

(Унаследовано от Object)
GetKeepAliveTime(TimeUnit)

Возвращает время сохранения активности потока, то есть время, когда потоки могут оставаться бездействующими перед завершением.

InvokeAll(ICollection)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от AbstractExecutorService)
InvokeAll(ICollection, Int64, TimeUnit)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от AbstractExecutorService)
InvokeAny(ICollection)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от AbstractExecutorService)
InvokeAny(ICollection, Int64, TimeUnit)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от AbstractExecutorService)
JavaFinalize()

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

(Унаследовано от Object)
NewTaskFor(ICallable)

RunnableFuture Возвращает объект для данной вызываемой задачи.

(Унаследовано от AbstractExecutorService)
NewTaskFor(IRunnable, Object)

RunnableFuture Возвращает значение для заданного значения runnable и по умолчанию.

(Унаследовано от AbstractExecutorService)
Notify()

Пробуждение одного потока, ожидающего монитора этого объекта.

(Унаследовано от Object)
NotifyAll()

Просыпает все потоки, ожидающие монитора этого объекта.

(Унаследовано от Object)
PrestartAllCoreThreads()

Запускает все основные потоки, что приводит к простой ожиданию работы.

PrestartCoreThread()

Запускает основной поток, что приводит к простой ожиданию работы.

Purge()

Пытается удалить из рабочей очереди все Future задачи, которые были отменены.

Remove(IRunnable)

Удаляет эту задачу из внутренней очереди исполнителя, если она присутствует, что приводит к тому, что она не будет запущена, если она еще не запущена.

SetHandle(IntPtr, JniHandleOwnership)

Задает свойство Handle.

(Унаследовано от Object)
SetKeepAliveTime(Int64, TimeUnit)

Задает время сохранения активности потока, то есть время, когда потоки могут оставаться бездействующими перед завершением.

Shutdown()

Инициирует упорядоченное завершение работы, в котором выполняются ранее отправленные задачи, но новые задачи не будут приняты.

ShutdownNow()

Пытается остановить все активно выполняемые задачи, останавливает обработку задач ожидания и возвращает список задач, ожидающих выполнения.

Submit(ICallable)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от AbstractExecutorService)
Submit(IRunnable)

Отправляет задачу Runnable для выполнения и возвращает будущее, представляющее задачу.

(Унаследовано от AbstractExecutorService)
Submit(IRunnable, Object)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от AbstractExecutorService)
Terminated()

Метод вызывается при завершении выполнения исполнителя.

ToArray<T>()

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
ToString()

Возвращает строковое представление объекта.

(Унаследовано от Object)
UnregisterFromRuntime()

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
Wait()

Приводит к тому, что текущий поток будет ждать, пока он не проснется, как правило, при <>помощи уведомления</em> или <эм>прерванного</em>.

(Унаследовано от Object)
Wait(Int64)

Приводит к тому, что текущий поток будет ждать, пока он не проснется, как правило, при <>получении уведомления</>em или <>эм прервано< или> до тех пор, пока не истекло определенное количество реального времени.

(Унаследовано от Object)
Wait(Int64, Int32)

Приводит к тому, что текущий поток будет ждать, пока он не проснется, как правило, при <>получении уведомления</>em или <>эм прервано< или> до тех пор, пока не истекло определенное количество реального времени.

(Унаследовано от Object)

Явные реализации интерфейса

IJavaPeerable.Disposed()

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
IJavaPeerable.DisposeUnlessReferenced()

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
IJavaPeerable.Finalized()

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
IJavaPeerable.JniManagedPeerState

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
IJavaPeerable.SetJniIdentityHashCode(Int32)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
IJavaPeerable.SetJniManagedPeerState(JniManagedPeerStates)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)
IJavaPeerable.SetPeerReference(JniObjectReference)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

(Унаследовано от Object)

Методы расширения

JavaCast<TResult>(IJavaObject)

Выполняет преобразование типа, проверяемого средой выполнения Android.

JavaCast<TResult>(IJavaObject)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

GetJniTypeName(IJavaPeerable)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

AwaitTerminationAsync(IExecutorService, Int64, TimeUnit)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

InvokeAnyAsync(IExecutorService, ICollection)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

InvokeAnyAsync(IExecutorService, ICollection, Int64, TimeUnit)

При ExecutorService выполнении каждой отправленной задачи используется один из нескольких пуловых потоков, обычно настроенный с помощью Executors методов фабрики.

Применяется к