2011-09-02 4 views
12

Je me demande comment Tomcat 7 implémente le traitement asynchrone. Je comprends que le thread de demande retourne immédiatement, permettant au thread de demande d'écouter immédiatement une nouvelle demande et y répondre.Tomcat 7 Traitement asynchrone

Comment la requête 'async' est-elle gérée? Y a-t-il un pool de threads séparé qui gère les requêtes asynchrones? Je suppose que le blocage IO est géré en utilisant quelque chose comme java.nio.Selector pour la performance. Qu'en est-il des threads qui bloquent les calculs du CPU?

+0

Vous pouvez jeter un oeil à ceci: http://stackoverflow.com/questions/ 7749350/illegalstateexception-not-supported-on-asynccontext-startasyncreq-res si vous voulez implémenter le traitement asynchrone sur Tomcat 7. Il y a une torsion. – JVerstry

Répondre

37

Vous mélangez différents concepts. Il faut distinguer entre:

  1. remise de demande Asynchronous selon Servlet 3.0; une API qui vous permet de découpler une demande de servlet entrante du pool de threads du conteneur Web. Il ne crée aucun fil à la volée. C'est à l'utilisateur de l'interface de mettre en œuvre une solution multi-thread appropriée. Cela ne concerne pas les entrées/sorties non bloquantes.
  2. Groupe de threads; fournit un mécanisme pour obtenir et gérer les threads dans un conteneur Web. Quand il s'agit de la demande asynchrone remise des demandes vous avez 2 options. Vous pouvez définir votre propre ExecutorService et l'utiliser pour traiter davantage la demande. Vous pouvez également créer un nouveau Runnable et le soumettre au AsyncContext obtenu en appelant le . Dans le cas de Tomcat, cette dernière approche utilise le pool de threads de Tomcat défini dans server.xml.
  3. E/S non bloquantes (NIO); Bien qu'il soit asynchrone aussi bien c'est une histoire différente. Elle concerne les opérations d'E/S non bloquantes telles que les E/S disque ou réseau. Si vous souhaitez activer NIO pour le traitement des requêtes HTTP, jetez un oeil à documentation de Tomcat.

L'exemple ci-dessous donne un aperçu comment il peut travail. Il utilise un seul thread pour les tâches de travail. Si vous exécutez à partir de 2 différents navigateurs en parallèle la sortie ressemble à ceci (j'utiliser un enregistreur personnalisé):

DATE       THREAD_ID LEVEL  MESSAGE 
2011-09-03 11:51:22.198 +0200  26  I:  >doGet: chrome 
2011-09-03 11:51:22.204 +0200  26  I:  <doGet: chrome 
2011-09-03 11:51:22.204 +0200  28  I:  >run: chrome 
2011-09-03 11:51:27.908 +0200  29  I:  >doGet: firefox 
2011-09-03 11:51:27.908 +0200  29  I:  <doGet: firefox 
2011-09-03 11:51:32.227 +0200  28  I:  <run: chrome 
2011-09-03 11:51:32.228 +0200  28  I:  >run: firefox 
2011-09-03 11:51:42.244 +0200  28  I:  <run: firefox 

Vous voyez que les méthodes doGet terminent immédiatement, alors que le travailleur court encore. Les 2 demandes de test: http://localhost:8080/pc/TestServlet?name=chrome et http://localhost:8080/pc/TestServlet?name=firefox.

Exemple simple Servlet

@WebServlet(asyncSupported = true, value = "/TestServlet", loadOnStartup = 1) 
public class TestServlet extends HttpServlet { 
    private static final Logger LOG = Logger.getLogger(TestServlet.class.getName()); 
    private static final long serialVersionUID = 1L; 
    private static final int NUM_WORKER_THREADS = 1; 

    private ExecutorService executor = null; 

    @Override 
    public void init() throws ServletException { 
     this.executor = Executors.newFixedThreadPool(NUM_WORKER_THREADS); 
    } 

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 

     final String name = request.getParameter("name"); 
     LOG.info(">doGet: " + name); 

     AsyncContext ac = request.startAsync(); // obtain async context 
     ac.setTimeout(0); // test only, no timeout 

     /* Create a worker */ 
     Runnable worker = new TestWorker(name, ac); 

     /* use your own executor service to execute a worker thread (TestWorker) */ 
     this.executorService.execute(worker); 

     /* OR delegate to the container */ 
     // ac.start(worker); 

     LOG.info("<doGet: " + name); 
    } 
} 

... et le TestWorker

public class TestWorker implements Runnable { 
    private static final Logger LOG = Logger.getLogger(TestWorker.class.getName()); 
    private final String name; 
    private final AsyncContext context; 
    private final Date queued; 

    public TestWorker(String name, AsyncContext context) { 
     this.name = name; 
     this.context = context; 
     this.queued = new Date(System.currentTimeMillis()); 
    } 

    @Override 
    public void run() { 

     LOG.info(">run: " + name); 

     /* do some work for 10 sec */ 
     for (int i = 0; i < 100; i++) { 
      try { 
       Thread.sleep(100); 
      } catch (InterruptedException e) { 
       throw new RuntimeException(e); 
      } 
     } 

     ServletResponse response = this.context.getResponse(); 
     response.setContentType("text/plain"); 

     try { 
      PrintWriter out = response.getWriter(); 
      out.println("Name:\t\t" + this.name); 
      out.println("Queued:\t\t" + this.queued); 
      out.println("End:\t\t" + new Date(System.currentTimeMillis())); 
      out.println("Thread:\t\t" + Thread.currentThread().getId()); 
      out.flush(); 
     } catch (IOException e) { 
      throw new RuntimeException(e); 
     } 

     this.context.complete(); 

     LOG.info("<run: " + name); 
    } 
} 
+0

Merci pour la clarification. En ce qui concerne l'API CometProcessor, y a-t-il un thread qui interroge toutes les connexions en cours pour voir lequel a des "données disponibles pour la lecture"? Pour être précis, quel serait le nombre attendu de threads quand il y a 10 demandes vs 100 demandes? En supposant que ce sont des demandes qui ont reçu un événement BEGIN, mais qui n'ont pas reçu l'événement READ. http://tomcat.apache.org/tomcat-7.0-doc/aio.html –

+0

@John Si vous êtes satisfait de la réponse de la maison, vous devriez l'approuver.Votre question supplémentaire devrait être une nouvelle question (éventuellement, vous pouvez faire référence à celui-ci). – JVerstry

+0

HI @JVerstry, pour être honnête, je ne me sens pas entièrement satisfait de la réponse. Je n'ai toujours pas l'impression d'avoir une bonne compréhension de l'architecture de Tomcat pour le "traitement asynchrone". –

Questions connexes