Я хотел бы вызвать 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 веб-службы одновременно и как я могу это сделать, используя этот код в качестве примера. Я искал здесь несколько статей или даже ответов, но не понял, как это сделать. Спасибо за терпение.
Спасибо за комментарий, как я могу это сделать? Я читал много статей, но есть много разных реализаций, и я до сих пор не понял, какое из них лучше всего подходит для моего случая.
Взгляните на здесь, чтобы вы начали думать об этом. Кстати, я предполагаю, что вы не используете Android.
Нет, это веб-приложение, использующее Spring Boot




Параллелизм в 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 ...?
Похоже, что @Pankaj победил меня в этом
Вы можете использовать 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 являются:
call().
Бонусный шаг: Мне кажется, что три вызова веб-службы нужно выполнять в одном и том же порядке несколько раз (я не понимаю язык - это не английский). Для такого кода можно создать отдельный класс оркестратора в верхней части классов, созданных на шаге 1 реализации.
Этот класс оркестратора может расширять класс Thread и выполнять три вызова веб-службы. Теперь этот единственный класс можно запускать асинхронно, вместо того, чтобы делать три вызова веб-службы. Сохраняет модульность кода и устраняет сложность.
Небольшая предыстория: я написал этот ответ не только для того, чтобы ответить на вопрос OP, но и для того, чтобы задокументировать дизайн, который я сделал для очень похожей проблемы, которую я решил для домашнего собеседования. Это Многопоточный подсчет слов.
ваш ответ очень полезен. В этом примере, который я опубликовал, не имеет значения порядок, в котором вызываются веб-службы, но у меня будет новая реализация, в которой мне нужно будет дождаться ответа одного конкретного вызова, а затем вызвать другие веб-службы.
Вы можете создать отдельный рабочий поток, который будет обрабатывать каждый вызов веб-службы.