2012-04-09 10 views
18

Servlet API sagt über "AsyncContext.start":Was ist der Zweck von AsyncContext.start (...) in Servlet 3.0?

void start (java.lang.Runnable run)

Bewirkt, dass der Behälter einen Thread versenden, möglicherweise von einem Thread-Pool verwaltet wird, laufen die angegeben Runnable. Der Container kann geeignete Kontextinformationen an das Runnable weiterleiten.

Aus dieser Beschreibung ist nicht ersichtlich, wie es sich auf die Optimierung der Thread-Nutzung bezieht, wenn der Job gewartet werden muss.

In "Servlets & JSP", gibt Budi Kurniawan Beispiel für Servlet 3.0 Asynchron-Funktionen, wo er AsyncContext.start verwendet, ich vereinfachte Version des Beispiels zeigen werden:

public void doGet(...) { 
    final AsyncContext asyncContext = request.startAsync(); 

    asyncContext.start(new Runnable() {                         
     @ Override 
     public void run() { 
      // do some work here which involves waiting 
      ... 
      asyncContext.complete(); 
     } 
    }); 
} 

In den meisten anderen Beispiele, die ich habe met, die Service-Methode speichert den AsyncContext nur irgendwo und er wird woanders bearbeitet (zB durch einen Hintergrund-Thread). In diesem Beispiel sieht es so aus, als ob der Job gerade an einen anderen Thread übergeben wird, der die Anfrage abschließt. Wie ich es verstehe, ist es jetzt einfach der Worker Thread, der beim Warten Zeit verschwendet.

Erhalten Sie tatsächlich etwas, indem Sie den Job (der das Warten beinhaltet) von einem Thread an einen anderen übergeben? Wenn nicht, was ist der Zweck von AsyncContext.start(...)?

+0

Ich fragte mich das Gleiche! – Deadron

Antwort

14

Sie haben ein schlechtes Beispiel gefunden, IMHO. In der Tat war mir nicht einmal bewusst, AsyncContext.start() Existenz.

Ich hatte einen kurzen Blick auf, wie Jetty und Tomcat dies implementieren. Tatsächlich scheinen sie einen Thread-Pool zu haben, der asynchrone Aufrufe unabhängig voneinander behandelt.

Eine solche Verwendung der API gibt Ihnen nichts oder sehr wenig. Anstatt den HTTP-Thread zu blockieren, blockieren Sie einen anderen Thread-Pool. Ich kann mir also vorstellen, dass die Anwendung immer noch neue Verbindungen akzeptiert, aber das Problem bleibt bestehen - der Container kann nicht alle verarbeiten, da dieser zusätzliche Thread-Pool immer noch begrenzt ist.

Die ganzen Punkte von AsyncContext ist die Fähigkeit, mehr als eine Anfrage von einem einzigen Thread zu behandeln. Häufig benötigen Sie nur einen einzigen Thread, um Tausende von asynchronen Verbindungen zu verarbeiten - z. wenn genau ein Thread auf Daten wartet, die an mehrere Clients gesendet werden sollen. Siehe auch The Limited Usefulness of AsyncContext.start()

+0

Das habe ich vermutet. Vielen Dank! – Aivar

+0

Haben Sie von einer Änderung dieser Implementierung erfahren, seit Sie geantwortet haben? –

10

Ich hatte die gleiche Reaktion zuerst - wenn Sie gerade die Arbeit zu einem anderen Thread übergeben, was gewinnen Sie? Die Spezifikation hilft nicht viel zu erklären, warum dies eine gute Idee ist. Aber this post macht eine hervorragende Arbeit. Im Grunde genommen ist es so, dass der Server bei hoher Last elegant degradiert wird, anstatt nur durch das Fehlen von Threads zu scheitern. Die eigentliche Arbeit wird in einem Thread-Thread mit fester Größe erledigt, sodass der Server eine beliebige Anzahl von Anfragen annehmen kann, ohne dass ein Thread für jeden einzelnen Thread bis zum Abschluss geführt werden muss. Natürlich müssen Sie möglicherweise Ihre O/S-Einstellungen optimieren, um Tausende von Sockets gleichzeitig offen zu halten.

Sobald Sie diese Möglichkeit haben, können Sie die Comet (Server-Push) -Architektur, wo das Client-Javascript eine AJAX-Anfrage offen hält, einfacher nutzen, damit der Server sie sofort nach Auftreten eines Ereignisses benachrichtigen kann Ich muss den Server abfragen, um herauszufinden, ob etwas passiert ist.

0

Ein Grund, warum dies nützlich sein kann ist, wenn Sie den eingehenden Web-Thread freigeben möchten, einige andere Arbeit tun und nach getan - zurück zum Web-Thread (möglicherweise ein anderer Thread, aber immer noch aus dem Webserver-Pool) um den ursprünglichen Vorgang abzuschließen und eine Antwort an den Client zu senden.

Zum Beispiel:

1. ac = request.startAsync(); 
2. forward("some data", "another system"); // async outbound HTTP request 
3. (at this point, incoming servlet thread is released to handle other requests) 
4. (in some other, non-servlet thread, upon "forward" response arrival) 
    ac.start(new Runnable() { /* send response to the client */ }); 

Sie könnten natürlich Reaktion in dem nicht-Servlet-Thread senden, aber dies hat einen Nachteil - Sie nicht-Servlet Thread verwenden Servlet-typischen Operationen zu tun, was bedeutet, Sie ändern implizit die Balance zwischen der Menge an Thread-Power, die für die Servlet-Arbeit reserviert ist, und anderen Arbeiten.

Mit anderen Worten - es gibt Ihnen die Möglichkeit, Runnable in den Servlet-Thread-Pool zu buchen. Offensichtlich sind dies seltene Bedürfnisse, aber immer noch - es gibt einige Überlegungen für AsyncContext.start() -Methode.