Применение исполнителя в языке Java

Применение исполнителя в языке JavaВ параллельном API поддерживается средство, называемое исполнителем и предназначенное для создания потоков исполнения и управления ими.

В этом отношении исполнитель служит альтернативой управлению потоками исполне­ния средствами класса Thread.

В основу исполнителя положен интерфейс Executor, в котором определяется следующий метод:

void execute(Runnable )

В результате вызова этого метода исполняется указанный поток. Следовательно, метод execute() запускает указанный поток на исполнение.

Интерфейс ExecutorService расширяет интерфейс Executor, дополняя его методами, помогающими управлять исполнением потоков и контролировать их.

Например, в интерфейсе ExecutorService определяется метод shutdown(), об­щая форма которого приведена ниже. Этот метод останавливает все потоки ис­полнения, находящиеся в данный момент под управлением экземпляра интерфей­са ExecutorService.

void shutdown()

В интерфейсе ExecutorService определяются также методы, которые запу­скают потоки исполнения, возвращающие результаты, исполняют ряд потоков и определяют состояние остановки.

Некоторые из этих методов будут рассмотре­ны далее. Имеется также интерфейс ScheduledExecutorService, расширяющий интерфейс ExecutorService для поддержки планирования потоков исполнения.

Кроме того, в параллельном API имеются три предопределенных клас­са исполнителей: ThreadPoolExecutor, ScheduledThreadPoolExecutor и ForkJoinPool.

ThreadPoolExecutor реализует интерфейсы Executor и ExecutorService и обеспечивает поддержку управляемого пула потоков ис­полнения.

Класс ScheduledThreadPoolExecutor также реализует интерфейс ScheduledExecutorService для поддержки планирования пула потоков исполне­ния.

А класс ForkJoinPool реализует интерфейсы Executor и ExecutorService и применяется в каркасе Fork/Join Framework.

Executor очень важный интерфейс который используется в многопоточном программировании. Если вы не осилили статью, советую посмотреть видео который я добавил в конце статьи. Запасайтесь хорошими наушниками, у меня сейчас Monster Beats купил их здесь, по ценам все хорошо.

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

Это позволяет сократить нагрузку, связанную с созданием множества отдельных потоков. Хотя классы ThreadPoolExecutor и Scheduled ThreadPoolExecutor можно использовать напрямую, исполнитель чаще всего придется получать, вызывая один из следующих статических фабричных методов, определенных во вспомогательном классе Executors. Ниже приве­дены общие формы некоторых из этих методов.

static ExecutorService newCachedThreadPool()
static ExecutorService newFixedThreadPool(int _)
static ScheduledExecutorService newScheduledThreadPool(int _)

Метод newCachedThreadPool() создает пул потоков исполнения, который не только вводит потоки исполнения по мере необходимости, но и по возможности повторно использует их.

Метод newFixedThreadPool() создает пул потоков ис­полнения, состоящий из указанного количества_потоков. А метод newScheduledThreadPool() создает пул потоков исполнения, в котором можно осуществлять планирование потоков исполнения.

Каждый из них возвращает ссылку на интер­фейс ExecutorService, предназначенный для управления пулом потоков испол­нения.

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

//    

import java.util.concurrent.*;

class SimpleExec {

    public static void main(String args[]) {

    CountDownLatch cd1 = new CountDownLatch(5);
    CountDownLatch cd2 = new CountDownLatch(5);
    CountDownLatch cd3 = new CountDownLatch(5);
    CountDownLatch cd4 = new CountDownLatch(5);
    ExecutorService es = Executors.newFixedThreadPool(2);

    System.out.println(" ");

    //   
    es.execute(new MyThread(cd1, "A"));
    es.execute(new MyThread(cd2, "B"));
    es.execute(new MyThread(cd3, "C"));
    es.execute(new MyThread(cd4, "D"));

    try {
        cd1.await();
        cd2.await();
        cd3.await();
        cd4.await();
    } catch(InterruptedException exc) {
        System.out.println(exc);
    }

    es.shutdown();
    System.out.println(" ");
    }
}

class MyThread implements Runnable {
    String name;
    CountDownLatch latch;


    MyThread(CountDownLatch c, String n) {
    latch = c;
    name = n;

    new Thread(this);
    }

    public void run() {

    for(int i = 0; i < 5; i++) {
        System.out.println(name + ": " + i);
        latch.countDown();
    }
    }
}

Ниже приведен результат выполнения данной программы:

 
A: 0
A: 1
A: 2
B: 0
A: 3
B: 1
A: 4
B: 2
C: 0
B: 3
C: 1
B: 4
C: 2
D: 0
C: 3
D: 1
C: 4
D: 2
D: 3
D: 4
 

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

Вызов метода shutdown() очень важен. Если бы его не было в данной програм­ме, она не смогла бы завершиться, поскольку исполнитель оставался бы активным. Убедиться в этом можно, закомментировав вызов метода shutdown ( ) и посмо­трев, что из этого получится.

Интересное видео по теме:

Один комментарий на “Применение исполнителя в языке Java

  1. А в чем смысл конструкции new Thread(this) ?
    Поток не стартует. Ссылок на него нет. Первый кандидат на уборку. ExcecutorService создает свой отдельный поток ни как с этим не связанный.

    MyThread(CountDownLatch c, String n) {
    latch = c;
    name = n;

    new Thread(this);
    }

    конкретно

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *