Сервлет, который запускает поток только один раз для каждого посетителя

Эй, я хочу реализовать сервлет Java, который запускает поток только один раз для каждого отдельного пользователя. Даже при обновлении он не должен запускаться снова. Мой последний подход доставил мне некоторые проблемы, поэтому никакого кода ^^. Любые предложения по макету сервлета?

 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 для регулярной отправки сообщений в сервлет и получения статуса. Поток работает около 3 минут, сканируя некоторые данные last.fm.


person gausss    schedule 17.10.2012    source источник
comment
Можете ли вы опубликовать код, который вы пробовали?   -  person Sathish    schedule 17.10.2012
comment
Каким был ваш последний подход? Дайте некоторые детали/фрагменты кода. Только тогда мы сможем сказать вам, как его улучшить.   -  person The Dark Knight    schedule 17.10.2012
comment
Почему вы хотите создать тему для каждого пользователя? Я бы посчитал этот подход не масштабируемым, поскольку это означает, что если у вас есть 1000 пользователей, вам потребуется 1000 потоков (каждый со своим собственным стеком, который может сильно повредить вашей памяти).   -  person beny23    schedule 17.10.2012
comment
Если бы вы сказали нам цель более точно, возможно, мы могли бы предложить другой, надеюсь, лучший подход к тому, что вы хотите. Основная идея блокировки потоков для пользователей кажется мне очень необычной в мире Java EE. Обычно лучше позволить контейнеру управлять потоками и не иметь с ними дело.   -  person jabal    schedule 17.10.2012
comment
Так что у меня есть пользователи, которые регистрируются на моем сайте. После регистрации мне нужно просканировать некоторые данные lastfm из их аккаунта. Так что нет большой задачи. Чего я хочу избежать, так это того, что они нажимают кнопку «Обновить» в своем браузере и тем самым запускают новые потоки ^^ и, конечно, позволяют нескольким пользователям одновременно сканировать свои материалы.   -  person gausss    schedule 17.10.2012


Ответы (5)


Гипотетически это может быть реализовано путем создания Map<String,Thread>, а затем вызывается ваш сервлет, который пытается найти карту с помощью 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
  } 

}

Примечания:

  • это использует идентификатор сеанса, а не пользователей для связывания потоков
  • взгляните на ThreadPools, они великолепны
  • как заметил комментатор: вопросы синхронизации не рассматриваются в этом скетче
person jabal    schedule 17.10.2012
comment
В этом ответе есть проблема параллелизма: что произойдет, если в одном сеансе одновременно появятся 2 сообщения? - person Bruno Reis; 17.10.2012

Здесь вам понадобится прослушиватель сеанса. Метод sessionCreated() будет вызываться только один раз для каждого сеанса браузера. Таким образом, даже если пользователь обновит страницу, проблем не будет. Затем вы можете продолжить и запускать поток для каждого вызова метода sessionCreated().

person NiranjanBhat    schedule 17.10.2012

Реализуйте javax.servlet.SingleThreadModel => метод службы не будет выполняться одновременно. См. спецификацию сервлетов.

person Andrey    schedule 17.10.2012

Ваша первая задача — выяснить, как однозначно идентифицировать пользователей, например, как бы вы различали разных пользователей за прокси-шлюзом/шлюзом SOHO?

После того, как вы это сделаете, в основном у вас будет просто одноэлементный объект, обслуживающий карту пользователя ‹-> потока для вашего сервлета.

И затем мы переходим к проблеме масштабируемости, как упоминает @beny23 в комментарии выше... Я абсолютно согласен с сделанным замечанием - ваш подход не является разумным с точки зрения масштабируемости!

Ваше здоровье,

person Anders R. Bystrup    schedule 17.10.2012

Насколько я понимаю, вы хотите избежать параллельной обработки запросов от одного и того же пользователя. Я бы предложил вам другой подход: связать блокировку с каждым пользователем и сохранить ее в сеансе. И перед тем, как начать обработку запросов пользователей - попробуйте получить эту блокировку. Таким образом, текущий поток будет ждать, пока обрабатываются другие запросы от этого пользователя. (Используйте прослушиватель сеанса для сохранения блокировки при создании сеанса)

person stemm    schedule 17.10.2012