【问题标题】:How to while loop a method with async calls in Java thread如何在Java线程中循环使用异步调用的方法
【发布时间】:2021-08-14 03:02:53
【问题描述】:

我无法弄清楚如何使用内部异步方法实现方法循环。 当我循环该方法时,它会在方法内的所有异步调用完成之前递增。有没有办法处理这个?代码示例:

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换成了OkHttp网站上的例子,思路是一样的。

【问题讨论】:

  • 没有足够的信息来解决这个问题。你能做一个完整的可编译的例子吗?
  • 编辑了帖子。我无法完全理解为什么 thread.join() 不适用于带有异步调用的方法。我假设异步调用本身是作为小线程创建的,这可能是问题所在。我做错了什么。
  • 是的,您的异步逻辑不一定在您运行可运行文件的同一线程上运行。您可以尝试从该方法返回 CompletableFuture,然后对结果执行类似 CompletableFuture.allof() 的操作。 baeldung.com/java-completablefuture

标签: java multithreading asynchronous


【解决方案1】:

所以看起来正在发生的事情是您正在创建一个线程来启动异步任务不会阻塞。所以线程在异步任务运行和 Thread.join 返回时完成。

如果您想等待异步任务完成,您可以使用CountDownLatch

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 块中,以提高任务失败时调用它的机会。countDown 还需要在 onFailure 中调用以确保获得足够的许可。

【讨论】:

  • 你也应该在onFailure方法中做一个cdl.countDown(),否则发生错误时,主线程永远不会结束。
  • @matt 感谢您的详细回答!问题就解决了!
  • @McModknower 这是真的!我经过测试才意识到这一点。
猜你喜欢
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 2010-12-22
  • 2011-01-26
  • 2020-09-09
  • 2015-12-11
  • 1970-01-01
相关资源
最近更新 更多