Шаблон проектирования для обработки асинхронного ответа в Java

Я читал ответы от подобных Q & A

Как создать асинхронный HTTP-запрос в JAVA? | Схема проектирования асинхронного программирования

AsyncTask Android - шаблон дизайна и возвращаемые значения

Я вижу много решений, но никто меня не удовлетворяет.

Способ прослушивания

Как только результаты пойманы, обработка выполняется в методе onResult.

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

Это решение не совсем удовлетворяет мне, потому что я хочу обрабатывать результаты в основном методе. Я ненавижу этот интерфейс, потому что, когда ответ возвращается, он обрабатывается в onResult, что приводит к цепочкам обработки и не может вернуться к "основному" методу.

Способ сервлетов

public class SignGuestbookServlet extends HttpServlet {

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

Нет открытого кода Java, вызывающего сервлет. Вся конфигурация выполняется в файле 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);

Есть ли шаблон дизайна для обработки запроса async и ждать ответа, как указано выше? Другой путь, чем слушатель. Пожалуйста, не библиотека или рамки.

ИЗМЕНИТЬ Спасибо за ответы. Я не дал вам полную картину, поэтому я показал класс 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

Асинхронный код всегда может быть синхронным. Самый простой/самый грубый способ - сделать асинхронный вызов, а затем ввести цикл 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;
        }
    }
}

Вы также можете использовать CountDownLatch, как рекомендовано hakon answer. Это будет делать в основном то же самое. Я также предлагаю вам ознакомиться с java.util.concurrent пакетом для лучшего способа управления потоками. Наконец, только потому, что вы можете это сделать, это не делает его хорошей идеей. Если вы работаете с инфраструктурой, основанной на асинхронных обратных вызовах, вам, вероятно, намного лучше узнать, как эффективно использовать инфраструктуру, чем пытаться ее подорвать.

Ответ 2

Во-первых, вы не должны отклонять первые два метода, которые вы обсуждаете. Есть очень веские причины, по которым люди используют эти методы, и вы должны попытаться изучить их, а не создавать новые.

В противном случае вы должны посмотреть 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());

где responseGetter имеет тип Callable<Response> (вы должны реализовать метод public Response call()).

Ответ 3

Может ли CountDownLatch помочь вам? В основном методе вы вызываете getResponse, а затем countDownLatch.await(). Передайте счетчик обратного отсчета к методу getResponse, а затем обратный отсчет после получения результата getResponse из результата getResponse:

CountDownLatch latch = new CountDownLatch(1);
Response a = getResponse(latch);
latch.await();

latch = new CountDownLatch(1);
Response b = getResponse(latch);
latch.await();

process(a, b);

Ваш запрос getResponse должен вызвать latch.countDown() после того, как асинхронные части возвращают результат.

например:.

public Response getResponse(CountDownLatch latch) {
     someAsychBloc(final CountDownLatch latch) {
       do work
       latch.countDown();
    }
}

Ответ 4

По существу вам нужен "слушатель", независимо от того, что. Это происходит из-за того, что вы не знаете, КОГДА ваше возвратное сообщение вернется, если вообще (это один из недостатков асинхронной обработки... что делать, если вы не получите сообщение возврата).

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

Или вы можете сделать гибрид на этом, имея отдельный поток, который "опроса" (или тянет) зону ответа на вашей службе, чтобы увидеть, существует ли сообщение возврата.

Таким образом, на самом деле все дело в том, хотите ли вы больше использовать метод "pull" или "push" для извлечения сообщений.

Структура SCA (Service Component Architecture) может быть чем-то рассмотренным, но в зависимости от того, что вы делаете, это тоже может быть излишним. Но что-то подумать.

EDIT:

Я только что нашел это в Java SE 6 Javadocs, которые могут быть полезны. интерфейс CompletionService, который абстрагирует то, что вам нужно о → асинхронной работе. Я предлагаю вам взглянуть.

Ответ 5

Если вам нужен поток страниц в веб-приложении, вам нужно обрабатывать веб-способом: сохранение некоторых данных в сеансе или куки или скрытые поля и т.д.

Проблема, которую вы пытаетесь решить, насколько я понимаю, исходит не из асинхронности, а из protocole http-статуса без гражданства.

С уважением,  Стефан