Spring Boot использует @Async для реализации асинхронных вызовов для ускорения выполнения задач!

Spring Boot Java задняя часть

Что такое «асинхронный вызов»? «Асинхронный вызов» соответствует «синхронному вызову». Синхронный вызов означает, что программы выполняются последовательно в соответствии с определенным порядком, и каждая строка программы должна дождаться завершения выполнения предыдущей строки программы перед выполнением; асинхронный вызов означает что когда программа выполняется последовательно, она не ждет асинхронных вызовов Оператор возвращает результат и выполняет следующую программу.

Синхронный вызов

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

Определите класс Task, создайте три функции обработки для имитации операций трех задач, а время потребления операции выбирается случайным образом (в пределах 10 секунд).

@Slf4j
@Component
public class AsyncTasks {

    public static Random random = new Random();

    public void doTaskOne() throws Exception {
        log.info("开始做任务一");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务一,耗时:" + (end - start) + "毫秒");
    }

    public void doTaskTwo() throws Exception {
        log.info("开始做任务二");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务二,耗时:" + (end - start) + "毫秒");
    }

    public void doTaskThree() throws Exception {
        log.info("开始做任务三");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务三,耗时:" + (end - start) + "毫秒");
    }

}

В тестовом примере введите объект Task и выполните его в тестовом примере.doTaskOne,doTaskTwo,doTaskThreeтри функции.

@Slf4j
@SpringBootTest
public class Chapter75ApplicationTests {

    @Autowired
    private AsyncTasks asyncTasks;

    @Test
    public void test() throws Exception {
        asyncTasks.doTaskOne();
        asyncTasks.doTaskTwo();
        asyncTasks.doTaskThree();
    }

}

Выполните модульный тест и увидите вывод, аналогичный следующему:

2021-09-11 23:19:12.922  INFO 92539 --- [           main] com.didispace.chapter75.AsyncTasks       : 开始做任务一
2021-09-11 23:19:17.788  INFO 92539 --- [           main] com.didispace.chapter75.AsyncTasks       : 完成任务一,耗时:4865毫秒
2021-09-11 23:19:17.788  INFO 92539 --- [           main] com.didispace.chapter75.AsyncTasks       : 开始做任务二
2021-09-11 23:19:24.851  INFO 92539 --- [           main] com.didispace.chapter75.AsyncTasks       : 完成任务二,耗时:7063毫秒
2021-09-11 23:19:24.851  INFO 92539 --- [           main] com.didispace.chapter75.AsyncTasks       : 开始做任务三
2021-09-11 23:19:26.928  INFO 92539 --- [           main] com.didispace.chapter75.AsyncTasks       : 完成任务三,耗时:2076毫秒

Задача 1, Задача 2 и Задача 3 выполняются последовательно, другими словами, три функции doTaskOne, doTaskTwo и doTaskThree выполняются последовательно.

Асинхронный вызов

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

В Spring Boot нам просто нужно использовать@AsyncАннотация может просто изменить исходную синхронную функцию на асинхронную, а класс Task изменится на следующий режим:

@Slf4j
@Component
public class AsyncTasks {

    public static Random random = new Random();

    @Async
    public void doTaskOne() throws Exception {
        log.info("开始做任务一");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务一,耗时:" + (end - start) + "毫秒");
    }

    @Async
    public void doTaskTwo() throws Exception {
        log.info("开始做任务二");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务二,耗时:" + (end - start) + "毫秒");
    }

    @Async
    public void doTaskThree() throws Exception {
        log.info("开始做任务三");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务三,耗时:" + (end - start) + "毫秒");
    }

}

Чтобы аннотация @Async вступила в силу, @EnableAsync также необходимо настроить в основной программе Spring Boot следующим образом:

@EnableAsync
@SpringBootApplication
public class Chapter75Application {

    public static void main(String[] args) {
        SpringApplication.run(Chapter75Application.class, args);
    }

}

Модульные тесты могут выполняться повторно на этом этапе, и вы можете столкнуться с различными результатами, такими как:

  • Нет вывода, связанного с задачей

  • Есть некоторые выходы, связанные с задачами

  • Вывод не по порядку, связанный с задачей

  • Причина в том, что в настоящее времяdoTaskOne,doTaskTwo,doTaskThreeТри функции уже выполняются асинхронно. После асинхронного вызова основной программы основной программе все равно, завершено ли выполнение этих трех функций.Поскольку другого содержимого для выполнения нет, программа завершается автоматически, что приводит к неполному или отсутствию вывода содержимого, связанного с задачей. .

Примечание:@AsyncИзмененная функция не должна быть определена как статический тип, чтобы асинхронный вызов не вступил в силу.

Асинхронный обратный вызов

чтобыdoTaskOne,doTaskTwo,doTaskThreeЭто может закончиться нормально. Предположим, нам нужно посчитать общее время, затраченное на одновременное выполнение трех задач, для этого нужно дождаться, пока три вышеуказанные функции завершат настройку, зафиксировать время и вычислить результат.

Так как же определить, были ли выполнены три приведенных выше асинхронных вызова? нам нужно использоватьCompletableFuture<T>чтобы вернуть результат асинхронного вызова, измененный следующим образомdoTaskOneфункция:

    @Async
public CompletableFuture<String> doTaskOne() throws Exception {
    log.info("开始做任务一");
    long start = System.currentTimeMillis();
    Thread.sleep(random.nextInt(10000));
    long end = System.currentTimeMillis();
    log.info("完成任务一,耗时:" + (end - start) + "毫秒");
    return CompletableFuture.completedFuture("任务一完成");
}

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

@Test
public void test() throws Exception {
    long start = System.currentTimeMillis();

    CompletableFuture<String> task1 = asyncTasks.doTaskOne();
    CompletableFuture<String> task2 = asyncTasks.doTaskTwo();
    CompletableFuture<String> task3 = asyncTasks.doTaskThree();

    CompletableFuture.allOf(task1, task2, task3).join();

    long end = System.currentTimeMillis();

    log.info("任务全部完成,总耗时:" + (end - start) + "毫秒");
}

Посмотрите, какие изменения мы внесли:

  • Запишите время начала в начале тестового примера
  • При вызове трех асинхронных функций возвращайтеCompletableFuture<String>объект результата типа
  • пройти черезCompletableFuture.allOf(task1, task2, task3).join()Реализуйте эффект блокировки до завершения всех трех асинхронных задач.
  • После выполнения всех трех задач подсчитайте общее время, затраченное на одновременное выполнение трех задач, по времени окончания — времени начала.

Выполните приведенный выше модульный тест и увидите следующие результаты:

2021-09-11 23:33:38.842  INFO 95891 --- [         task-3] com.didispace.chapter75.AsyncTasks       : 开始做任务三
2021-09-11 23:33:38.842  INFO 95891 --- [         task-2] com.didispace.chapter75.AsyncTasks       : 开始做任务二
2021-09-11 23:33:38.842  INFO 95891 --- [         task-1] com.didispace.chapter75.AsyncTasks       : 开始做任务一
2021-09-11 23:33:45.155  INFO 95891 --- [         task-2] com.didispace.chapter75.AsyncTasks       : 完成任务二,耗时:6312毫秒
2021-09-11 23:33:47.308  INFO 95891 --- [         task-3] com.didispace.chapter75.AsyncTasks       : 完成任务三,耗时:8465毫秒
2021-09-11 23:33:47.403  INFO 95891 --- [         task-1] com.didispace.chapter75.AsyncTasks       : 完成任务一,耗时:8560毫秒
2021-09-11 23:33:47.404  INFO 95891 --- [           main] c.d.chapter75.Chapter75ApplicationTests  : 任务全部完成,总耗时:8590毫秒

Видно, что за счет асинхронных вызовов задачи 1, 2 и 3 выполняются одновременно, что эффективно сокращает общее время работы программы. Эта серия уроков«Основное руководство по Spring Boot 2.x» нажмите прямо!, добро пожаловать в избранное и вперед! Если вы столкнулись с трудностями в процессе обучения? может присоединиться к нашемуГруппа весеннего технического обмена, участвовать в обменах и обсуждениях, лучше учиться и прогрессировать!

пример кода

Полный проект этой статьи можно посмотреть на следующем складе2.xв каталогеchapter7-5проект:

Если вы считаете, что эта статья хороша, добро пожаловатьStarПоддержите, ваше внимание - движущая сила моего упорства!

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