在 Java 中处理异步响应的设计模式

2022-09-03 00:49:33

我从类似的问答中阅读了答案

如何在 JAVA 中创建异步 HTTP 请求?|异步编程设计模式|
AsyncTask Android - 设计模式和返回值

我看到了很多解决方案,但没有一个能真正让我满意。

监听方式

捕获结果后,将在 onResult 方法中实现处理。

public interface GeolocationListener {
public void onResult(Address[] addresses);
public void onError(Exception e);
}

这个解决方案并不能完全满足我,因为我想在main方法中处理结果。我讨厌这个接口,因为当返回响应时,它会在result中处理,从而导致处理链,并且无法返回“main”方法。

服务方式

public class SignGuestbookServlet extends HttpServlet {

    public void doPost(HttpServletRequest req, HttpServletResponse resp)
                throws IOException {
        // ...
        resp.sendRedirect("/guestbook.jsp");
    }
}

没有公开的 Java 代码调用 servlet。所有配置都是在 Web 中完成的.xml

我想要的方式

等待这样的响应

Response a = getResponse();
// wait until the response is received, do not go further
// process
Response b = getResponse();
// wait until the response is received, do not go further
process(a,b);

是否有设计模式来处理异步请求并等待如上所述的响应?除了听众之外,其他方式。请不要使用库或框架。

编辑感谢到目前为止的回应。我没有给你完整的画面,所以我公开了我开始实现的Geolocation类。我不知道如何实现该方法。有人可以展示“如何”吗?他(或她)还必须实现侦听器来检索结果

private Address getFullAddress (String text, AddressListener listener, ... ){

    // new Geolocation(text, listener, options).start() 
    // implements Geolocation.GeolocationListener   
    // how to return the Address from the onResult ?
}

答案 1

首先,你不应该拒绝你讨论的前两种方法。人们使用这些技术有很好的理由,你应该尝试学习它们,而不是创建新的技术。

否则,您应该查看java.util.concurrent

ExecutorService es = Executors.newFixedThreadPool(2);
...
Future<Response> responseA = es.submit(responseGetter);
Future<Response> responseB = es.submit(responseGetter);

process(responseA.get(), responseB.get());

其中 是类型(必须实现该方法)。responseGetterCallable<Response>public Response call()


答案 2

异步代码始终可以设置为同步。最简单/最粗糙的方法是进行异步调用,然后进入一个 while 循环,该循环仅休眠当前线程,直到值返回。

编辑:将异步回调转换为同步代码的代码 - 同样,这是一个粗略的实现:

import java.util.concurrent.*;

public class MakeAsynchronousCodeSynchronous {
    public static void main(String[] args) throws Exception {
        final Listener listener = new Listener();
        Runnable delayedTask = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new IllegalStateException("Shouldn't be interrupted", e);
                }
                listener.onResult(123);

            }
        };
        System.out.println(System.currentTimeMillis() + ": Starting task");
        Executors.newSingleThreadExecutor().submit(delayedTask);
        System.out.println(System.currentTimeMillis() + ": Waiting for task to finish");
        while (!listener.isDone()) {
            Thread.sleep(100);
        }
        System.out.println(System.currentTimeMillis() + ": Task finished; result=" + listener.getResult());
    }

    private static class Listener {
        private Integer result;
        private boolean done;

        public void onResult(Integer result) {
            this.result = result;
            this.done = true;
        }

        public boolean isDone() {
            return done;
        }

        public Integer getResult() {
            return result;
        }
    }
}

您也可以按照hakon的答案建议使用CountDownLatch。它基本上会做同样的事情。我还建议您熟悉java.util.concurrent包,以获得更好的方法来管理线程。最后,仅仅因为你可以做到这一点,并不能使它成为一个好主意。如果您使用的是基于异步回调的框架,那么学习如何有效地使用框架可能比尝试破坏它要好得多。


推荐