1

嘿,我想实现一个 Java Servlet,它只为每个用户启动一次线程。即使刷新它也不应该重新开始。我的最后一种方法给我带来了一些麻烦,所以没有代码^^。对 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);
}
}

jsp 使用 ajax 定期发布到 servlet 并获取状态。该线程只运行了 3 分钟,爬取了一些 last.fm 数据。

4

5 回答 5

1

您在这里需要的是Session listener。对于每个浏览器会话,该方法sessionCreated()只会被调用一次。因此,即使用户刷新页面,也不会有任何问题。然后,您可以继续为每个sessionCreated()方法调用启动线程。

于 2012-10-17T10:51:45.447 回答
1

实现 javax.servlet.SingleThreadModel => 服务方法不会被并发执行。请参阅 servlet 规范。

于 2012-10-17T10:59:08.643 回答
0

您的首要任务是弄清楚如何唯一地识别用户,例如,您将如何识别代理/SOHO 网关后面的不同用户?

一旦你把它弄下来,它基本上只是有一个单例对象为你的 servlet 提供用户<->线程映射。

然后我们进入@beny23 在上面的评论中提到的可扩展性问题......我完全同意所提出的观点 - 你的方法在可扩展性方面并不合理!

干杯,

于 2012-10-17T10:49:12.437 回答
0

据我了解,您希望避免并行处理来自同一用户的请求。我建议您使用其他方法:将 lock 与每个用户关联并将其存储在 session 中。在开始处理用户请求之前 - 尝试获取该锁。因此,当前线程将等待来自该用户的其他请求正在处理。(创建会话时使用会话监听器存储锁)

于 2012-10-17T10:50:36.153 回答
0

假设它可以通过创建一个来实现Map<String,Thread>,然后你的 servlet 被调用,它会尝试使用sessionId.

只是一个草图:

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
  } 

}

笔记:

  • 这使用会话 ID,而不是用户来关联线程
  • 看看ThreadPools,他们很棒
  • 正如评论者指出的那样:此草图中未考虑同步问题
于 2012-10-17T10:52:41.280 回答