Асинхронная обработка = связующие потоки = действительный? - PullRequest
2 голосов
/ 11 мая 2010

мне разрешено (без каких-либо побочных эффектов) создавать и запускать new Thread() из doGet() Method сервлета? Или это как-то утечка ресурсов?

Допустимо ли также передавать объект "Session" в поток, чтобы позже сохранить результат моей асинхронной обработки (я буду синхронизирован правильно) в сеансе? Или эта утечка будет использовать при использовании сеанса "в независимых потоках"?

=> Что бы произошло, если бы сессия истекла сессию, поскольку у нее истекло время ожидания, и я получу к ней доступ из своего потока? Или это также может привести к побочному эффекту, заключающемуся в том, что хранение сеанса в потоке не позволит веб-контейнеру вообще прекратить сеанс (и, следовательно, в конечном итоге утечка ресурсов, поскольку сеансы не очищаются)?

(я знаю, что есть и другие решения, например, работа с записями DB- (Job), JMS или Servlets 3.0), но мне нужно решить эту проблему, как описано, добавив новый поток в doGet.)

Большое спасибо! Jens

Ответы [ 4 ]

0 голосов
/ 12 мая 2010

мне разрешено (без каких-либо побочных эффектов) создавать и запускать новый Thread () из метода сервлета doGet ()?

Если хорошо реализовано, это нормально.

Допустимо ли также передавать объект "Session" в поток, чтобы позже сохранить результат моей асинхронной обработки (я буду синхронизирован правильно) в сеансе?

Я бы этого не делал. Скорее сохраните Thread в сеансе. Таким образом, вы всегда можете получить его при последующих запросах, когда это необходимо.

Что произойдет, если время сеанса истечет через веб-контейнер, поскольку у него истекло время ожидания, и я получу к нему доступ из своего потока? Или это также может привести к побочному эффекту, заключающемуся в том, что хранение сеанса в потоке не позволит веб-контейнеру вообще прекратить сеанс (и, следовательно, в конечном итоге утечка ресурсов, поскольку сеансы не очищаются)?

Сессия истечет (и GC'ed, если вы сделаете , а не хранит ссылку на него в вашем Thread), но поток продолжит работу, пока не вернется из метода run(). Обычной практикой является регулярная проверка себя в методе run() на предмет прерывания потока или нет (например, один раз на каждом шаге или во время каждого 1% прогресса). Вы можете реализовать HttpSessionBindingListener, чтобы сигнализировать о прерывании по окончании сеанса.

public class Task extends Thread implements HttpSessionBindingListener {

    public void run() {
        while (true) {
            someHeavyStuff();
            if (isInterrupted()) return;
        }
    }

    public void valueBound(HttpSessionBindingEvent event) {
        start(); // Will instantly be started when doing session.setAttribute("task", new Task());
    }

    public void valueUnbound(HttpSessionBindingEvent event) {
        interrupt(); // Will signal interrupt when session expires.
    }

}
0 голосов
/ 11 мая 2010

Хотя это считается плохой практикой, оно работает для небольших проектов. Лучшим решением является использование ExecutorService для выполнения работы (даже если вы создаете синглтон, который содержит ExectorService). Этот подход должен соответствовать пулам потоков, предоставляемым сервером приложений (хотя я не пробовал).

Внутри вашего сервлета сделайте что-то вроде:

Future future = myExecutorService.submit(new Task(workRequest));
session.put("result", future);

Я бы также не передавал объект Session пользователя сервису, так как реализация сеанса может включать ThreadLocal. Вместо этого исполнитель создает объект Future, который вы можете поместить в сеанс. Таким образом, вы можете проверить, не завершено ли позднее ваше асинхронное вычисление (или отменить или дождаться его).

Future future = session.get("result");
boolean isDone = future.isDone();
boolean isCancelled = future.isCancelled();
showInJSP(isDone, isCancelled);
0 голосов
/ 12 мая 2010

Во-первых, то, что вы хотите сделать, будет ВЕРОЯТНО работать.Зависит от целого ряда вещей.Но с системой с небольшой нагрузкой, несколькими запросами и т. Д. Она, вероятно, будет работать нормально.

Что касается проблемы с истечением срока действия сеанса, то шансы «ничего не произойдет».Вы с радостью будете хранить и ссылаться на информацию, на которую больше никто не смотрит.

Наивно сервер завершит сеанс и удалит объект Session из своей внутренней карты.Между тем, ваш поток будет хранить ссылку на него и не будет знать, хорош ли сеанс или нет.

На загруженном сервере система может взять информацию о сеансе пользователя и сериализовать ее.на диск.Когда пользователь вернется, он прочтет его обратно. В этом случае вы будете ссылаться на «старый, сиротский» сеанс, который, опять же, пользователь больше никогда не увидит.

Когда вашпоток умирает, сессия уйдет вместе с потоком.

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

Да, это всеограничения на вашу технику, она не делает технику неправильной, она просто ограничивает реализацию.Если ваше приложение и служба могут нормально работать с этими ограничениями, вы великолепны, и не беспокойтесь об этом.

0 голосов
/ 11 мая 2010

Создание нового потока из сервлета считается плохой практикой. Обычной альтернативой порождению новых потоков является использование JMS / MDB для асинхронной обработки.

...