Search code examples
javamultithreadingservletsmulti-user

Servlet that starts a thread only once for every visitor


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.


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