Выпущено в JDK 5Executors framework(java.util.concurrent.Executor) для запускаRunnable
Object, нет необходимости каждый раз создавать новый поток, как раньше, в большинстве случаев будет повторно использоваться уже созданный поток.
Все мы знаем, что есть два способа создать поток в java. Если вы хотите узнать больше об их сравнении, прочитайтеэта статья. Создание потоков в java — очень затратный процесс, который также включает в себя накладные расходы памяти. Итак, если мы можем повторно использовать эти потоки, чтобы запуститьRunnable
Можно сэкономить больше ресурсов.
В этой статье я напишу несколько примеров программ, демонстрирующих, как использоватьExecutor
framework, а затем мы обсудим некоторые рекомендации, которые следует учитывать при разработке многопоточных программ.
Если вы хотите узнать больше о другой многопоточной информации, нажмите здесьСсылка на сайт.
Базовый пример использования
В нашем примере программы запущены две задачи, и ни одна из них не должна прекращать выполнение, и обе задачи выполняются в фиксированной среде. Я попытаюсь написать класс-оболочку, чтобы:
- Если какая-либо задача выдает исключение, программа поймает его и перезапустит задачу.
- Если какая-либо задача завершилась, программа уведомит об этом и перезапустит задачу.
Ниже приведен пример кода программы:
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 ! ");
}
}
Лучшие практики, которым необходимо следовать
- Всегда используйте какой-нибудь инструмент статического анализа для запуска кода Java, напримерPMDиFindBugsвыявить более глубокие проблемы, которые более полезны при определении сложных сценариев, которые могут возникнуть в будущем.
- Всегда проводите взаимные обзоры кода со старшими разработчиками для облегчения поиска в коде.тупикИли лайвлок, добавьте в программу монитор работоспособности для проверки состояния запущенной задачи, и это хороший способ в большинстве сцен.
- Заведите привычку отлавливать ошибки, а не только исключения, при написании многопоточных приложений. Иногда случаются неожиданные вещи, возможно, Java выдает ошибку, это не исключение.
- С переключателем отката, если программа дает сбой, это может быть невосстановимо, вам не нужно спешить, чтобы запустить еще один цикл, чтобы обострить ситуацию, вместо этого вы должны дождаться восстановления программы, прежде чем начинать заново.
- Обратите внимание, что исполнители, по своей сути, абстрагируются от деталей выполнения, поэтому порядок не гарантируется, если это явно не указано.
Удачной учебы!
- Предыдущий:Обработка исключений с использованием внутренних классов
- Следующий:5 причин рассмотреть возможность миграции устаревших систем
- Каталог серий:Лучшие практики программирования на Java
Оригинальный источник: https://howtodoinjava.com/core-java/multi-threading/java-executor-framework-tutorial-and-best-practices
Зависит откороль хорошийперевести