Как в то время как цикл метода с асинхронными вызовами в потоке Java

#java #multithreading #asynchronous

Вопрос:

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

 void runEngine() {
    for(range) {
        someAsyncCall();
    }
}


void main() {
    Runnable r = () -> {
       runEngine();
    };
    while(!stop) {
        Thread t1 = new Thread(r);
        t1.start();
        t1.setDaemon(false);
        t1.join();
    }
}
 

Подробный Пример:

 package com.abc;

import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;

public class SomeClass{
    private final OkHttpClient client = new OkHttpClient();
    static void asyncCall() {
        Request request = new Request.Builder()
                .url("http://publicobject.com/helloworld.txt")
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override public void onResponse(Call call, Response response) throws IOException {
                try (ResponseBody responseBody = response.body()) {
                    if (!response.isSuccessful()) throw new IOException("Unexpected code "   response);

                    Headers responseHeaders = response.headers();
                    for (int i = 0, size = responseHeaders.size(); i < size; i  ) {
                        System.out.println(responseHeaders.name(i)   ": "   responseHeaders.value(i));
                    }

                    System.out.println(responseBody.string());
                }
            }
        });
    }
    static void runEngine() {
        for(int k = 0; k < 100; k  ) {
            asyncCall();
        }
    }


    public static void main(String[] args) throws InterruptedException {
        Runnable r = () -> {
            runEngine();
        };
        while(true) {
            Thread t1 = new Thread(r);
            t1.start();
            t1.setDaemon(false);
            t1.join();
        }
    }
}
 

Я заменил свой asyncCall примером, взятым с сайта OHTTP, идея та же.

Комментарии:

1. Для решения этой проблемы недостаточно информации. Можете ли вы привести полный компилируемый пример.

2. Отредактировал сообщение. Я не могу полностью понять, почему thread.join() не работает с методом с асинхронными вызовами. Я предполагаю, что сами асинхронные вызовы изначально создаются в виде небольших потоков, что может быть проблемой. Я делаю что-то не так.

3. Да, ваша асинхронная логика не обязательно выполняется в том же потоке, в котором у вас есть запускаемый. Вы можете попробовать вернуть CompletableFuture из метода, а затем сделать что-то вроде CompletableFuture.allof() для результатов. baeldung.com/java-completablefuture

Ответ №1:

Итак, похоже, что вы создаете поток, который запускает асинхронные задачи, которые не блокируются. Таким образом, поток завершается во время выполнения асинхронных задач и потока.регистрация возвращается.

Если вы хотите дождаться завершения асинхронных задач, вы можете использовать обратный отсчет.

 static void runEngine() throws InterruptException {
    int n = 100;
    CountDownLatch cdl = new CountDownLatch(n);
    for(int k = 0; k < n; k  ) {
        asyncCall(cdl);
    }
    cdl.await();
}
 

Я сделал защелку обратного отсчета аргументом с тех пор, как вы использовали статические методы.

     static void asyncCall(CountDownLatch cdl) {
        Request request = new Request.Builder()
                .url("http://publicobject.com/helloworld.txt")
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                cdl.countDown();
            }

            @Override public void onResponse(Call call, Response response) throws IOException {
                try (ResponseBody responseBody = response.body()) {
                    if (!response.isSuccessful()) throw new IOException("Unexpected code "   response);

                    Headers responseHeaders = response.headers();
                    for (int i = 0, size = responseHeaders.size(); i < size; i  ) {
                        System.out.println(responseHeaders.name(i)   ": "   responseHeaders.value(i));
                    }

                    System.out.println(responseBody.string());
                } finally{
                    cdl.countDown();
                }
            }
        });
    }
 

Теперь отправлен блок асинхронных задач, и поток будет блокироваться до тех пор, пока не будет вызвано 100 из них CoundDownLatch.countDown() .Я отложил обратный отсчет в блоке finally, чтобы повысить вероятность того, что он будет вызван, когда ваша задача завершится неудачей.обратный отсчет также необходимо вызвать в OnFailure, чтобы убедиться, что получено достаточно разрешений.

Комментарии:

1. вы также должны выполнить cdl.обратный отсчет() в методе OnFailure, иначе при возникновении ошибки основной поток никогда не завершится.

2. @matt Спасибо за подробный ответ! Вот и решена проблема!

3. @McModknower, это правда! Мне потребовался тест, чтобы понять это.