Введение. Для асинхронного вызова метода с 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 напрямую?