Почему Alibaba не рекомендует использовать аннотацию Async напрямую?

задняя часть
Почему Alibaba не рекомендует использовать аннотацию Async напрямую?

Введение. Для асинхронного вызова метода с Spring 3 предоставляется аннотация @Async, которую можно пометить в методе для асинхронного вызова метода. Вызывающий объект вернется сразу после вызова, а фактическое выполнение метода будет передано задаче Spring TaskExecutor для выполнения потоками в указанном пуле потоков.

В приложениях проекта @Async вызывает пул потоков, и рекомендуется использовать режим пользовательского пула потоков. Общие решения для пользовательских пулов потоков: повторно реализовать интерфейс AsyncConfigurer.

Сценарии применения

Синхронизация: Синхронизация — это последовательное выполнение всего процесса обработки.По завершении каждого процесса возвращается результат.

Асинхронный: асинхронный вызов просто отправляет инструкцию вызова, и вызывающей стороне не нужно ждать полного выполнения вызываемого метода; вместо этого он продолжает выполнять следующий процесс. Например, в определенном вызове три метода процесса A, B и C должны вызываться последовательно; если все они являются синхронными вызовами, они должны выполняться последовательно, прежде чем они будут засчитаны как завершение процесса; если B является асинхронным методом вызова, после выполнения A, вызовите B, и не ждите завершения B, а начните вызывать C. После того, как C выполнен, это означает, что процесс завершен. В Java при работе с подобными сценариями это обычно основано на создании независимых потоков для завершения соответствующей логики асинхронного вызова, а также на процессе выполнения между основным потоком и различными бизнес-подпотоками после запуска независимого потока. основной поток продолжает выполнение, не останавливаясь в ожидании.

Spring реализовал пул потоков

  • SimpleAsyncTaskExecutor: не настоящий пул потоков, этот класс не использует повторно потоки, по умолчанию новый поток создается каждый раз, когда он вызывается.
  • SyncTaskExecutor: этот класс не реализует асинхронный вызов, а только синхронную операцию. Полезно только там, где многопоточность не требуется.
  • ConcurrentTaskExecutor: Класс адаптации Executor, не рекомендуется. Если ThreadPoolTaskExecutor не соответствует требованиям, рассмотрите возможность использования только этого класса.
  • SimpleThreadPoolTaskExecutor: это класс SimpleThreadPool от Quartz. Этот класс требуется только тогда, когда пул потоков используется как кварцем, так и не кварцем.
  • **ThreadPoolTaskExecuto**r : Чаще всего используется, рекомендуется. Суть его в обертке для java.util.concurrent.ThreadPoolExecutor.

Асинхронные методы

  • Простейший асинхронный вызов, возвращаемое значение void
  • Асинхронный вызов с параметрами, асинхронные методы могут передавать параметры
  • Существует возвращаемое значение, и его часто вызывают для возврата Future.

Включить @Async весной

**

**

@Async применяет пул потоков по умолчанию

Spring применяет пул потоков по умолчанию, что означает, что имя пула потоков не указывается при использовании аннотации @Async. Глядя на исходный код, пул потоков по умолчанию для @Async:SimpleAsyncTaskExecutor.

  • Вызов без возвращаемого значения

На основе вызова @Async без возвращаемого значения добавьте аннотации непосредственно к классу и методу (рекомендуется использовать метод). Если вам нужно создать исключение, вам нужно вручную создать новое исключение.

  • Есть возвращаемое значение Будущий вызов

  • имеет возвращаемое значениеCompletableFutureперечислить

**CompletableFuture** Не используйте аннотацию @Async для достижения функции вызова пула системных потоков для обработки бизнеса.

JDK5 добавил интерфейс Future для описания результата асинхронного вычисления. Хотя Future и родственные методы использования предоставляют возможность асинхронного выполнения задач, получить результат очень неудобно, а результат задачи можно получить только путем блокировки или опроса. Метод блокировки явно противоречит первоначальному замыслу нашего асинхронного программирования, метод опроса будет потреблять ненужные ресурсы процессора, а результаты вычислений не могут быть получены вовремя.

  • CompletionStage представляет собой определенный этап в асинхронном вычислительном процессе. После завершения одного этапа может быть запущен другой этап.

  • Стадия выполнения вычислений может быть Function, Consumer или Runnable. Например:

    stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.println())

  • Выполнение этапа может быть инициировано завершением одного этапа или несколькими этапами одновременно.

В Java8,CompletableFutureОн предоставляет очень мощную функцию расширения Future, которая может помочь нам упростить сложность асинхронного программирования, и предоставляет возможность функционального программирования, которое может обрабатывать результаты вычислений посредством обратных вызовов, а также предоставляет методы для преобразования и объединения CompletableFuture.

  • Он может представлять собой явно завершенное будущее или этап завершения (CompletionStage), который поддерживает запуск некоторых функций или выполнение некоторых действий после завершения расчета.

  • Он реализует Будущее иCompletionStageинтерфейс

  • Недостатки пула потоков по умолчанию

В приложении пула потоков см. спецификацию разработки Java для Alibaba:Пулы потоков не могут использовать Executors для создания, не разрешается использовать пул потоков по умолчанию в системе. Рекомендуется использовать метод ThreadPoolExecutor. Этот метод обработки позволяет инженеру-разработчику более четко представлять правила работы пула потоков и избегать риска исчерпания ресурсов. . Недостатки каждого метода Исполнителей:

  • newFixedThreadPool и newSingleThreadExecutor: Основная проблема в том, что накопленная очередь обработки запросов может потреблять очень большой объем памяти, даже OOM.
  • newCachedThreadPool и newScheduledThreadPool: основная проблема заключается в том, что максимальное количество потоков равно Integer.MAX_VALUE, что может создать очень большое количество потоков, даже OOM.

Асинхронная конфигурация @Async по умолчанию использует SimpleAsyncTaskExecutor. Пул потоков создает поток для задачи по умолчанию. Если потоки постоянно создаются в системе, система в конечном итоге займет слишком много памяти и вызовет ошибку OutOfMemoryError. В ответ на проблему создания потока SimpleAsyncTaskExecutor предоставляет текущий механизм ограничения, который управляет переключением через атрибут concurrencyLimit.Когда concurrencyLimit>=0, текущий механизм ограничения включен, а текущий механизм ограничения по умолчанию то есть concurrencyLimit=-1.Когда он выключен, он будет продолжать создавать новые потоки для обработки задач. В соответствии с конфигурацией по умолчанию SimpleAsyncTaskExecutor не является строго пулом потоков и не может реализовать функцию повторного использования потоков.

@Async применяет пользовательский пул потоков

Пользовательский пул потоков может более детально управлять пулом потоков в системе, и удобно настраивать конфигурацию размера пула потоков, а также контроль и обработку исключений выполнения потоков. При настройке системного пользовательского пула потоков для замены пула потоков по умолчанию, хотя его можно установить с помощью различных режимов, пул потоков, окончательно сгенерированный путем замены пула потоков по умолчанию, имеет один и только один (не может установить несколько классов для наследования AsyncConfigurer) пользовательский пул потоков Существуют следующие режимы:

  • Переопределите интерфейс AsyncConfigurer.
  • Наследовать AsyncConfigurerSupport
  • Настройте встроенный исполнитель задач, который будет заменен настраиваемым TaskExecutor.

При просмотре правил вызова @Async по умолчанию в исходном коде Spring класс, реализующий интерфейс AsyncConfigurer в исходном коде, будет запрашиваться первым, а класс, реализующий этот интерфейс, — AsyncConfigurerSupport. Однако настроенный по умолчанию пул потоков и метод асинхронной обработки пусты, поэтому для наследования или повторной реализации интерфейса необходимо указать пул потоков. И переопределите метод public Executor getAsyncExecutor().

  • Реализовать интерфейс AsyncConfigurer

  • Наследовать AsyncConfigurerSupport

  • Настройте собственный TaskExecutor

Поскольку пул потоков по умолчанию AsyncConfigurer в исходном коде пуст, Spring сначала проверяет, существует ли пул потоков через beanFactory.getBean(TaskExecutor.class).Если он не настроен, он проверяет, существует ли пул потоков по умолчанию через beanFactory. .getBean(DEFAULT_TASK_EXECUTOR_BEAN_NAME, Executor.class) Пул потоков с именем TaskExecutor. Поэтому в проекте определите bean-компонент с именем TaskExecutor для создания пула потоков по умолчанию. Вы также можете объявить пул потоков, не указывая имя пула потоков.Сам нижний уровень основан на TaskExecutor.class.

Например:

Executor.class:ThreadPoolExecutorAdapter->ThreadPoolExecutor->AbstractExecutorService->ExecutorService->Executor

В таком режиме последним нижним слоем является Executor.class.При замене пула потоков по умолчанию необходимо установить имя пула потоков по умолчанию на TaskExecutor.

TaskExecutor.class:ThreadPoolTaskExecutor->SchedulingTaskExecutor->AsyncTaskExecutor->TaskExecutor

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

Другие технические статьи, которыми можно поделиться, поиск в WeChat: Архитектура Code Farmer

Оригинальный адрес:Почему Alibaba не рекомендует использовать аннотацию Async напрямую?