Лучшие практики Java Executor Framework | Секреты разработчика Develop Paper

Java
Лучшие практики Java Executor Framework | Секреты разработчика Develop Paper

Выпущено в JDK 5Executors framework(java.util.concurrent.Executor) для запускаRunnableObject, нет необходимости каждый раз создавать новый поток, как раньше, в большинстве случаев будет повторно использоваться уже созданный поток.

Все мы знаем, что есть два способа создать поток в java. Если вы хотите узнать больше об их сравнении, прочитайтеэта статья. Создание потоков в java — очень затратный процесс, который также включает в себя накладные расходы памяти. Итак, если мы можем повторно использовать эти потоки, чтобы запуститьRunnableМожно сэкономить больше ресурсов.

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

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

Базовый пример использования

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

  1. Если какая-либо задача выдает исключение, программа поймает его и перезапустит задачу.
  2. Если какая-либо задача завершилась, программа уведомит об этом и перезапустит задачу.

Ниже приведен пример кода программы:

package com.devcheats.multithreading.executors;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class DemoExecutorUsage {

    private static ExecutorService executor = null;
    private static volatile Future taskOneResults = null;
    private static volatile Future taskTwoResults = null;

    public static void main(String[] args) {
        executor = Executors.newFixedThreadPool(2);
        while (true) {
            try {
                checkTasks();
                Thread.sleep(1000);
            } catch (Exception e) {
                System.err.println("Caught exception: " + e.getMessage());
            }
        }
    }

    private static void checkTasks() throws Exception {
        if (taskOneResults == null
                || taskOneResults.isDone()
                || taskOneResults.isCancelled()) {
            taskOneResults = executor.submit(new TestOne());
        }

        if (taskTwoResults == null
                || taskTwoResults.isDone()
                || taskTwoResults.isCancelled()) {
            taskTwoResults = executor.submit(new TestTwo());
        }
    }
}

class TestOne implements Runnable {
    public void run() {
        while (true) {
            System.out.println("Executing task one");
            try {
                Thread.sleep(1000);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }

    }
}

class TestTwo implements Runnable {
    public void run() {
        while (true) {
            System.out.println("Executing task two");
            try {
                Thread.sleep(1000);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }
}

Пожалуйста, не забудьте прочитать Best Practices в конце статьи.

Выполнение нескольких задач в одном потоке

Каждый Runnable не обязательно должен выполняться в отдельном потоке. Иногда нам нужно выполнить несколько задач в одном потоке, каждая задача является экземпляром Runnable. Для разработки такого типа решения следует использовать многопроходную систему. Этот multi-runnable — это просто набор runnables, которые необходимо выполнить. Кроме того, этот multi-runnable сам по себе является Runnable.

Ниже приведен список задач, которые необходимо выполнить в одном потоке.

Не нужно выполнять каждый потокRunnable.有时候我们需要在一个线程中执行多个任务,每个任务都是一个Runnableпример. Чтобы спроектировать программу такого типа, вы должны создать несколькоRunnable,ЭтиRunnableпредставляет собой набор задач, которые необходимо выполнить. Кроме того, этоRunnableСам сборник тожеRunnableпример.

Вот код, который необходимо выполнить несколько задач в одном потоке:

package com.devcheats.multithreading.executors;

public class TaskOne implements Runnable {
    @Override
    public void run() {
        System.out.println("Executing Task One");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class TaskTwo implements Runnable {
    @Override
    public void run() {
        System.out.println("Executing Task Two");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class TaskThree implements Runnable {
    @Override
    public void run() {
        System.out.println("Executing Task Three");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Создаем многозадачную обертку

package com.devcheats.demo.multithreading;

import java.util.List;

public class MultiRunnable implements Runnable {

    private final List<Runnable> runnables;

    public MultiRunnable(List<Runnable> runnables) {
        this.runnables = runnables;
    }

    @Override
    public void run() {
        for (Runnable runnable : runnables) {
             new Thread(runnable).start();
        }
    }
}

Теперь описанную выше многопоточность можно выполнить, как следующую программу:

package com.devcheats.demo.multithreading;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MultiTaskExecutor {

    public static void main(String[] args) {

        BlockingQueue<Runnable> worksQueue = new ArrayBlockingQueue<Runnable>(10);
        RejectedExecutionHandler rejectionHandler = new RejectedExecutionHandelerImpl();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 3, 10, TimeUnit.SECONDS, worksQueue, rejectionHandler);

        executor.prestartAllCoreThreads();

        List<Runnable> taskGroup = new ArrayList<Runnable>();
        taskGroup.add(new TestOne());
        taskGroup.add(new TestTwo());
        taskGroup.add(new TestThree());

        worksQueue.add(new MultiRunnable(taskGroup));
    }
}

class RejectedExecutionHandelerImpl implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
        System.out.println(runnable.toString() + " : I've been rejected ! ");
    }
}

Лучшие практики, которым необходимо следовать

  1. Всегда используйте какой-нибудь инструмент статического анализа для запуска кода Java, напримерPMDиFindBugsвыявить более глубокие проблемы, которые более полезны при определении сложных сценариев, которые могут возникнуть в будущем.
  2. Всегда проводите взаимные обзоры кода со старшими разработчиками для облегчения поиска в коде.тупикИли лайвлок, добавьте в программу монитор работоспособности для проверки состояния запущенной задачи, и это хороший способ в большинстве сцен.
  3. Заведите привычку отлавливать ошибки, а не только исключения, при написании многопоточных приложений. Иногда случаются неожиданные вещи, возможно, Java выдает ошибку, это не исключение.
  4. С переключателем отката, если программа дает сбой, это может быть невосстановимо, вам не нужно спешить, чтобы запустить еще один цикл, чтобы обострить ситуацию, вместо этого вы должны дождаться восстановления программы, прежде чем начинать заново.
  5. Обратите внимание, что исполнители, по своей сути, абстрагируются от деталей выполнения, поэтому порядок не гарантируется, если это явно не указано.

Удачной учебы!


Оригинальный источник: https://howtodoinjava.com/core-java/multi-threading/java-executor-framework-tutorial-and-best-practices

Зависит откороль хорошийперевести