Вызов нескольких веб-сервисов одновременно с использованием Java

Я хотел бы вызвать 3 веб-службы одним и тем же методом, и каждый результат будет установлен в объекте, как это показано ниже:

public Dossie procuraPorCPF(String cpf) {

    Dossie dossie = new Dossie();

    // first webservice call
    dossie.setCnh(detectaClientCnh.verificaCNH(cpf));

    // second webservice call
    dossie.setFotoCnh(detectaClientCnhFoto.verificaFotoCNHPorCpf(cpf));

    // third webservice call
    dossie.setPm(consultaPMWService.getPMPorCPF(cpf).getProcuraPMPorCPFResult());

    return dossie;
}

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

Вы можете создать отдельный рабочий поток, который будет обрабатывать каждый вызов веб-службы.

Tim Biegeleisen 22.07.2018 04:10

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

Murilo Góes de Almeida 22.07.2018 04:16

Взгляните на здесь, чтобы вы начали думать об этом. Кстати, я предполагаю, что вы не используете Android.

Tim Biegeleisen 22.07.2018 04:17

Нет, это веб-приложение, использующее Spring Boot

Murilo Góes de Almeida 22.07.2018 04:25
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
4
317
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Параллелизм в Java обрабатывается через класс Thread. Конструктор Thread принимает параметр Runnable с кодом для запуска Thread. Когда вызывается метод start(), JVM создает новый поток и выполняет код метода run()Runnable.

Поскольку Runnable имеет только один абстрактный метод run(), вы можете использовать лямбда-выражение для более читаемого кода. Я использовал традиционный синтаксис для первого вызова и лямбда-синтаксис для двух других, чтобы продемонстрировать оба метода.

public Dossie procuraPorCPF(String cpf) {
    Dossie dossie = new Dossie();
    Thread[] threads = new Thread[3];

    threads[0] = new Thread(new Runnable() {
        @Override
        public void run() {
            dossie.setCnh(detectaClientCnh.verificaCNH(cpf));
        }
    };
    threads[0].start();

    threads[1] = new Thread(() ->
        dossie.setFotoCnh(detectaClientCnhFoto.verificaFotoCNHPorCpf(cpf));
    threads[1].start();

    threads[2] = new Thread(() ->
        dossie.setPm(consultaPMWService.getPMPorCPF(cpf).getProcuraPMPorCPFResult());
    threads[2].start();

    try {
        threads[0].join();
        threads[1].join();
        threads[2].join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    return dossie;
}

Метод join() блокирует выполнение программы до тех пор, пока вызывающий Thread не завершит работу. Поместив join() в конец метода, вы можете гарантировать, что все 3 запроса будут выполнены до того, как вы вернетесь. Если не имеет значения, завершились ли эти запросы до того, как вы вернетесь, вы можете просто удалить join(), и запросы будут продолжаться в фоновом режиме, пока выполняется остальная часть вашего приложения.

Для более крупных приложений Java также включает пулы потоков, который будет управлять созданием Thread за вас. Поскольку ваше приложение использует только те же 3 Runnable в локальном контексте, я думаю, что приведенное выше решение лучше подходит (и более образовательно для целей этого ответа).

Спасибо, этот код решит мою проблему. Не могли бы вы продемонстрировать, как сделать то же самое, используя такие функции Java8, как Future, FutureTask, Callable ...?

Murilo Góes de Almeida 22.07.2018 11:45

Похоже, что @Pankaj победил меня в этом

Elan Hamburger 22.07.2018 16:37
Ответ принят как подходящий

Вы можете использовать ExecutorService для отправки Callable и вызвать Future.get () для получения результата, как показано ниже (измените Future <String> на соответствующее возвращаемое значение). Вам также следует подумать об обработке ошибок и создании пула потоков вне метода (если это возможно при запуске приложения).

public Dossie procuraPorCPF(String cpf) {

    ExecutorService executor = Executors.newFixedThreadPool(3);

    Future<String> cnh = executor.submit(() -> detectaClientCnh.verificaCNH(cpf));
    Future<String> fotoCnh = executor.submit(() -> detectaClientCnhFoto.verificaFotoCNHPorCpf(cpf));
    Future<String> pm =
        executor.submit(() -> consultaPMWService.getPMPorCPF(cpf).getProcuraPMPorCPFResult());

    Dossie dossie = new Dossie();

    try {
      dossie.setCnh(cnh.get());
      dossie.setFotoCnh(fotoCnh.get());
      dossie.setPm(pm.get());
    } catch (InterruptedException | ExecutionException cause) {
      cause.printStackTrace();
    }
    executor.shutdown();
    return dossie;
  }

I started writing this answer in the night and then left it for the next day. By the morning two answers were given and one of those was accepted by OP. Leaving this answer here for anyone who wishes to see the complete design and idea of the implementation, instead of actual code.


Дизайн:

Поскольку для ответа на вызовы веб-службы требуется время, они вызываются асинхронно, что означает, что основной поток не синхронизируется с этими вызовами.

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

В вашем случае важными элементами Java являются:

  1. Вызываемый интерфейс;
  2. Будущий интерфейс;
  3. ExecutorService.

Реализация:

  1. Реализуйте класс, который extends реализует интерфейс Callable и содержит вызывающий код для веб-службы в методе call().
    • Сделайте это для всех трех вызовов веб-служб;
  2. Запустите ExecutorService, который будет выполнять этот вызов и собирать результаты за вас;
  3. Когда вам нужно сделать вызов, создайте экземпляр из трех вызовов и сохраните их в ArrayList;
  4. Используя ExecutorService, созданный на шаге 2, вызовите экземпляры, созданные на шаге 3.

Бонусный шаг: Мне кажется, что три вызова веб-службы нужно выполнять в одном и том же порядке несколько раз (я не понимаю язык - это не английский). Для такого кода можно создать отдельный класс оркестратора в верхней части классов, созданных на шаге 1 реализации.

Этот класс оркестратора может расширять класс Thread и выполнять три вызова веб-службы. Теперь этот единственный класс можно запускать асинхронно, вместо того, чтобы делать три вызова веб-службы. Сохраняет модульность кода и устраняет сложность.

Небольшая предыстория: я написал этот ответ не только для того, чтобы ответить на вопрос OP, но и для того, чтобы задокументировать дизайн, который я сделал для очень похожей проблемы, которую я решил для домашнего собеседования. Это Многопоточный подсчет слов.

displayName 22.07.2018 19:30

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

Murilo Góes de Almeida 22.07.2018 19:42

Другие вопросы по теме