10 maja 2012

Wątki podczas obsługi asynchronicznego żądania w Servlet 3.0 i IBM WebSphere Application Server 8.0.0.3

Kontynuując moje rozpoznawanie mechanizmów asynchronicznego przetwarzania żądań w Servlet 3.0, tym razem przysiadłem, aby rozpoznać ich obsługę w serwerze aplikacyjnym IBM WebSphere Application Server 8.0.0.3. Stworzyłem servlet, który wyświetla wątki uczestniczące w zadaniu.
package pl.japila;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = "/AsyncServlet", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

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

        // Record the servlet's thread
        PrintWriter out = response.getWriter();
        out.printf("<h3>Servlet's thread: %s</h3>", Thread.currentThread());
        out.flush();
        
        // Put the request into asynchronous mode
        request.startAsync();

        // Run an asynchronous task via servlet 3.0's abstractions
        AsyncContext asyncCtx = request.getAsyncContext();
        MyTask mt = new MyTask(asyncCtx);
        asyncCtx.start(mt);
        
        // Run another asynchronous task via java's abstractions
        MyTask mt02 = new MyTask(asyncCtx);
        new Thread(mt02).start();

        out.printf("<h3>Servlet finishes its job</h3>");
    }

    public class MyTask implements Runnable {

        AsyncContext asyncContext;

        public MyTask(AsyncContext asyncContext) {
            this.asyncContext = asyncContext;
        }

        @Override
        public void run() {
            ServletResponse response = asyncContext.getResponse();
            try {
                // do the time-consuming job
                PrintWriter out = response.getWriter();
                for (int i = 0; i < 5; i++) {
                    out.printf("<h2>Hello from thread: %s (%d)</h2>", Thread.currentThread(), i);
                    out.flush();
                    Thread.sleep(1 /* secs */ * 1000);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                asyncContext.complete();
            }
        }
    }
}
Czy widział(a)byś usprawnienia w tym servlecie?

Komentarz Tomka mógłby świadczyć o niepoprawności takiego podejścia, ale w moim przekonaniu jedynym obecnie problemem jest tworzenie wątku każdorazowo po otrzymaniu żądania i opcjonalnie brak określenia czasu oczekiwania na zakończenie. Alternatywnym i sądzę, że możliwym podejściem jest tworzenie pseudo-wątku za pomocą java.util.concurrent.Callable i skorzystanie z mechanizmów oferowanych przez pakiet java.util.concurrent. Na chwilę obecną wiem, że to możliwe (konsultant), ale nie wiem, jak to zrealizować (specjalista).

Wcześniejsze wpisy o przetwarzaniu asynchronicznym w Servlet 3.0:
Jego uruchomienie skutkuje wyświetleniem strony z uczestniczącymi wątkami. Uważam, że podział na dedykowane pule wątków w WASie, które można osobno stroić do potrzeb aplikacji, prezentuje się obiecująco.


A jak to wygląda na Twoim serwerze aplikacyjnym? Ciekawym wyników z GlassFish 3.1.2, JBoss AS 7.1.1, Apache Tomcat 7.0.27, Oracle WebLogic Server 12c i in. Wyniki można słać na priv, albo zamieścić bezpośrednio w komentarzu do tego wpisu. Gorąco zachęcam.