#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, это правда! Мне потребовался тест, чтобы понять это.