JUGLviv

Meta


Share on:


Многопоточность в Java: ExecutorService

JUG LvivJUG Lviv

В Java 5 было добавлено много вещей для организации многопоточности и особенно касаемо организации параллельного доступа. В этой и последующих статьях мы пройдемся по некоторыми из них.

ExecutorService


До Java 5 для организации работы с несколькими потоками приходилось использовать сторонние имплеменации пулинга или писать свой. С появлением ExecutorService такая необходимость отпала.

ExecutorService исполняет асинхронный код в одном или нескольких потоках. Создание инстанса ExecutorService’а делается либо вручную через конкретные имплементации (ScheduledThreadPoolExecutor илиThreadPoolExecutor), но проще будет использовать фабрики класса Executors. Например, если надо создать пул с 2мя потоками, то делается это так:

ExecutorService service = Executors.newFixedThreadPool(2);


Если требуется использовать кэширующий пул потоков, который создает потоки по мере необходимости, но переиспользует неактивные потоки (и подчищает потоки, которые были неактивные некоторое время), то это задается следующим образом:

ExecutorService service = Executors.newCachedThreadPool();


Теперь небольшой пример. Допустим, надо запустить какой-нибудь код асинхронно 10 раз. Основываясь на вышесказанном, код будет выглядеть так:

ExecutorService service = Executors.newCachedThreadPool();
for(int i = 0; i < 10; i++) {
 service.submit(new Runnable() {
  public void run() {
   // snip... piece of code
  }
 });
}


Метод submit также возвращает объект Future, который содержит информацию о статусе исполнения переданного Runnable или Callable (который может возвращать значение). Из него можно узнать выполнился ли переданный код успешно, или он еще выполняется. Вызов метода get на объекте Futureвозвратит значение, который возвращает Callable (или null, если используется Runnable). Метод имеет 2 checked-исключения: InterruptedException, который бросается, когда выполнение прервано через методinterrupt(), или ExecutionException если код в Runnable или Callable бросил RuntimeException, что решает проблему поддержки исключений между потоками.

ScheduledExecutorService


Иногда требуется выполнение кода асихронно и периодически или требуется выполнить код через некоторое время, тогда на помощь приходит ScheduledExecutorService. Он позволяет поставить код выполняться в одном или нескольких потоках и сконфигурировать интервал или время, на которое выполненение будет отложено. Интервалом может быть время между двумя последовательными запусками или время между окончанием одного выполнения и началом другого. Методы ScheduledExecutorServiceвозвращают ScheduledFuture, который также содержит значение отсрочки для выполнения ScheduledFuture.

Например, если требуется отложить выполнение на 5 секунд, потребуется следующий код:

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.schedule(new Runnable() { ... }, 5, TimeUnit.SECONDS);


Если требуется назначить выполнение каждую секунду:

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(new Runnable() { ... }, 0, 1, TimeUnit.SECONDS);


И, наконец, если требуется назначить выполнение кода с промежутком 1 секунда между выполнениями:

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleWithFixedDelay(new Runnable() { ... }, 0, 1, TimeUnit.SECONDS);

Взято звідси 

Bitnami