views:

108

answers:

4

Hello Experts,

am I allowed (without any sideeffects) to create and start a new Thread() from within a doGet() Method of a servlet? Or does this somehow leak ressources?

Is it valid to also pass the "Session" Object into the Thread to later save the result of my asynchronous processing (I will synchronized correctly) in the session? Or will this leak ressources when using the session "in indepedant threads"?

=> What would happen if the session meanwhile would be expired by the webcontainer as it has timedout and I will access it from my thread? Or would could this also lead to the sideffect, that storing the session in the thread will prevent the webcontainer from expiring the session at all (and therefore finally leak ressources as the sessions do not get cleared up)?

(I know there are other Solutions, like working with DB-(Job)Records, JMS or Servlets 3.0) but I need so solve the problem as described by spanning a new Thread within doGet.)

Thank you very much!! Jens

A: 

Creating a new thread from within a servlet is considered bad practice. The usual alternative to spawning new threads is using JMS/MDB's for asynchronous processing.

Taylor Leese
Why is it bad practice?
Skip Head
Well, thread management should be delegated to the application server. Also, take a look at the Google App Engine restrictions which disallow creating threads (see http://code.google.com/appengine/docs/java/runtime.html#The_Sandbox). It's a performance issue basically.
Taylor Leese
Thanks, Taylor L.
Skip Head
A: 

While considered bad practice, it works for small scale projects. A better solution is to use an ExecutorService to perform the work (even if you create a singleton which holds the ExectorService). This approach should be consistent with application server provided thread pools (though i've not tried it).

From within your servlet do something like:

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

I would also not pass the user Session object to the service, since the implementation of the session may involve ThreadLocal. Instead the executor produces a Future object which you can put into the session. That way, you can test to see if your asynchronous computation is finished later on (or cancel or wait for it).

Future future = session.get("result");
boolean isDone = future.isDone();
boolean isCancelled = future.isCancelled();
showInJSP(isDone, isCancelled);
Justin
Yes, JMS is what most people use.
Justin
Future's aren't serializable (well, they could be, but the interface doesn't require it). Just mentioning for the fun and laughs this will bring up when you try to failover the server instance in a cluster.
Will Hartung
The OP does not seem to be interested in failover.
Justin
A: 

First off, what you want to do will PROBABLY work. Depends on a whole bunch of things. But with a system with little load, few requests, etc., it will probably work fine.

Regarding your Session expiration issue, odds are "nothing will happen". You will happily store and reference information that nobody else is looking at.

Naively, the server will expire the session, and remove the Session object from its internal map. Meanwhile, your thread will keep a reference to it, and won't be the wiser of whether the Session is good or bad.

On a loaded server, the system might take the users Session information and serialize it out to disk. When the user comes back, it'll read it back in. In that case, you'll be referring to the "old, orphan" Session that, again, the User will never see again.

When your thread dies, the Session will Go Away along with the thread.

So, basically, as long as you have a single instance of the server, that you don't cluster, that your server doesn't swap out sessions, that the server doesn't restart (this is another point where the server might save and restore sessions), and the session doesn't time out -- you should be good.

Yes, those are all limitations on your technique, it doesn't make the technique wrong, it just constrains the implementation. If your application and service can work fine within those constraints, you're golden, and don't worry about it.

Will Hartung
A: 

am I allowed (without any sideeffects) to create and start a new Thread() from within a doGet() Method of a servlet?

If well implemented, this is fine.

Is it valid to also pass the "Session" Object into the Thread to later save the result of my asynchronous processing (I will synchronized correctly) in the session?

I wouldn't do that. Rather store the Thread in session. This way you can always grab it back on subsequent requests whenever needed.

What would happen if the session meanwhile would be expired by the webcontainer as it has timedout and I will access it from my thread? Or would could this also lead to the sideffect, that storing the session in the thread will prevent the webcontainer from expiring the session at all (and therefore finally leak ressources as the sessions do not get cleared up)?

The session will be expired (and GC'ed if you do not hold a reference to it in your Thread), but the thread will continue running until it returns from run() method. The normal practice is to check regularly yourself in the run() method if the thread is interrupted or not (e.g. once during every step or during every 1% progress). You can implement HttpSessionBindingListener to signal an interrupt when the session has been expired.

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.
    }

}
BalusC