web-dev-qa-db-ja.com

Java)で非同期応答を処理するためのデザインパターン

同様のQ&Aから回答を読みました

JAVAで非同期HTTPリクエストを作成するにはどうすればよいですか? | 非同期プログラミングデザインパターン |
AsyncTask Android-デザインパターンと戻り値

私は多くの解決策を見ていますが、どれも私を本当に満足させません。

リスナーウェイ

結果が取得されると、処理はonResultメソッドに実装されます。

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

Mainメソッドで結果を処理したいので、このソリューションは私を完全には満足させません。応答が返されると、onResultで処理され、処理のチェーンが発生し、「main」メソッドに戻る方法がないため、このインターフェイスは嫌いです。

サーブレットウェイ

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);

非同期リクエストを処理し、上記のような応答を待つデザインパターンはありますか?リスナー以外の方法。ライブラリやフレームワークは使用しないでください。

[〜#〜]編集[〜#〜]これまでの回答に感謝します。全体像を説明しなかったので、実装を開始した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 ?
}
17
Raymond Chenon

非同期コードは常に同期させることができます。最も簡単で最も粗雑な方法は、非同期呼び出しを行ってから、値が戻るまで現在のスレッドをスリープ状態にする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 package に精通することをお勧めします。最後に、あなたできるからといって、これは良い考えにはなりません。非同期コールバックに基づくフレームワークを使用している場合は、フレームワークを破壊しようとするよりも、フレームワークを効果的に使用する方法を学ぶ方がはるかに良いでしょう。

9
Ryan Stewart

まず、最初の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()を実装する必要があります)。

11
toto2

CountDownLatch お役に立てますか? mainメソッドでは、getResponseを呼び出してからcountDownLatch.await()を呼び出します。カウントダウンラッチを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();
    }
}
6
hakon

基本的に、何があっても、ある種の「リスナー」が必要です。これは、返信メッセージがいつ返されるかがわからないためです(これは、非同期処理の欠点の1つです...返信メッセージが表示されない場合の対処方法)。

したがって、イベントを待機するリスナーを実装する必要があります(つまり、返されるメッセージによって処理されるように微調整されます)。

または、サービスの応答領域を「ポーリング」(またはプル)して戻りメッセージが存在するかどうかを確認する別のスレッドを作成することで、そのハイブリッドを実行できます。

したがって、メッセージを取得するための「プル」メソッドと「プッシュ」メソッドのどちらが必要かということになります。

SCA(Service Component Architecture) フレームワークは考慮すべき点かもしれませんが、実行していることによっては、やり過ぎになる可能性もあります。しかし、考慮すべきことがあります。

編集:

これはJava SE 6 Javadocsで役立つかもしれません。インターフェース CompletionService これはあなたが気にかけていることそのものを抽象化します->非同期作業です。あなたが見てください。

1
Chris Aldrich

Webアプリケーションでページフローが必要な場合は、Webの方法で処理する必要があります。つまり、セッション、Cookie、非表示フィールドなどにデータを保存します。

私が理解している限り、あなたが取り組もうとしている問題は、非同期性からではなく、ステートレスhttpプロトコルから来ています。

よろしく、ステファン

0
Snicolas