Question

Hey I want to implement a Java Servlet that starts a thread only once for every single user. Even on refresh it should not start again. My last approach brought me some trouble so no code^^. Any Suggestions for the layout of the servlet?

 public class LoaderServlet extends HttpServlet {
// The thread to load the needed information
private LoaderThread loader;
// The last.fm account
private String lfmaccount;

public LoaderServlet() {
    super();
    lfmaccount = "";
}

@Override
protected void doPost(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    if (loader != null) {
        response.setContentType("text/plain");
        response.setHeader("Cache-Control", "no-cache");
        PrintWriter out = response.getWriter();
        out.write(loader.getStatus());
        out.flush();
        out.close();
    } else {
        loader = new LoaderThread(lfmaccount);
        loader.start();
        request.getRequestDispatcher("WEB-INF/pages/loader.jsp").forward(
                request, response);
    }
}

@Override
protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    if (lfmaccount.isEmpty()) {
        lfmaccount = request.getSession().getAttribute("lfmUser")
                .toString();
    }
    request.getRequestDispatcher("WEB-INF/pages/loader.jsp").forward(
            request, response);
}
}

The jsp uses ajax to regularly post to the servlet and get the status. The thread just runs like 3 minutes, crawling some last.fm data.

Était-ce utile?

La solution

Hypothetically it could be implemented by creating a Map<String,Thread> and then your servlet gets called it tries to look up the map with the sessionId.

Just a sketch:

public class LoaderServlet extends HttpServlet {

  private Map<String,Thread> threadMap = new HashMap<>();

  protected void doPost(..) {
    String sessionId = request.getSesion().getId();
    Thread u = null;
    if(threadMap.containsKey()) {
        u = threadMap.get(sessionId);
    } else {
       u = new Thread(...);
       threadMap.put(sessionId, u);
    }
    // use thread 'u' as you wish
  } 

}

Notes:

  • this uses session id's, not users to associate threads
  • have a look at ThreadPools, they are great
  • as a commenter pointed out: synchronization issues are not considered in this sketch

Autres conseils

What you need here is Session listener. The method sessionCreated() will be called only once for every browser session. So, even if the user refreshes the page, there will be no issues. You can then go ahead and start the thread for every sessionCreated() method call.

Implement javax.servlet.SingleThreadModel => the service method will not be executed concurrently. See the servlets specification.

Your first task is to figure out how to identify users uniquely, for instance how would you discern different users behind a proxy/SOHO gateway?

Once you have that down it's basically just having a singleton object serving a user<->thread map to your servlet.

And then we get into the scalability issue as @beny23 mentions in a comment above... I absolutely concur with the point made - your approach is not sound scalability-wise!

Cheers,

As I understand, you want to avoid parallel processing of requests from the same user. I'd suggest you other approach: associate lock with each user and store it in session. And before start processing of users request - try to get that lock. So current thread will wait while other requests from this user are handling. (Use session listener to store lock, when session is created)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top