struts-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Andrew Hill" <andrew.david.h...@gridnode.com>
Subject RE: multithreaded env
Date Fri, 20 Dec 2002 08:20:33 GMT
A webapp running in a servlet container (this includes any struts app) is by
nature multithreaded.

As you know, in a struts app most of the work is done not in servlets you
implement, but rather in Action classes.

These are also multithreaded. Struts will create a single instance of your
Action and all requests for that Action will be processed by that instance.
This means that at any given moment you could have any number of threads
simultaneously running that Action's code.

The implication of this is that you have to be careful of what you do with
class member variables. (ie. Dont use them!)

for example, consider the following rather contrived Action:

public class WotsitAction extends Action
{
  private String _foo; //member variable - Dangerous!

  public ActionForward execute(ActionMapping mapping, ActionForm actionForm,
                               HttpServletRequest request,
HttpServletResponse response)
  	throws Exception
  {
    WotsitForm wotsitForm = (WotsitForm)form;
    _foo = wotsitForm.getFoo(); //line 1
    doSomething(_foo); //line 2
    //etc....
  }
}

Now let us imagine we have two users who both submit different values for
foo at nearly the same instant. User A submits a value of "A", and User B
submits a value of "B". Let us assume that user A submits first. The action
code is invoked and line 1 causes _foo to be set to "A".

Meanwhile user B has also submitted. His request goes to the same instance
of the WotsitAction.

Let us imagine that user B's thread executes line 1 a picosecond after user
A, just before user A's thread starts line 2. As a result _foo is now set to
"B", because both threads are sharing the same action instance and thus the
same _foo variable.

Now BOTH users threads will be using the value of "B" to doSomething(). This
is obviously not what we intended...

Whats rather scary about this is that the errors that will result may well
not be picked up in your basic testing, but rather will surface much later
when load testing is conducted, or even worse when the app is in production.
They will be intermittent errors and could take a considerable amount of
time to track down...

In this example for the code to work as intended it is necessary that the
member variable _foo is replaced by a method variable. Ie:

public class WotsitAction extends Action
{
  public ActionForward execute(ActionMapping mapping, ActionForm actionForm,
                               HttpServletRequest request,
HttpServletResponse response)
  	throws Exception
  {
    WotsitForm wotsitForm = (WotsitForm)form;
    String foo = wotsitForm.getFoo(); //line 1
    doSomething(foo); //line 2
    //etc....
  }
}

In this case both threads still share the action instance, but foo is now
local to the execute method and each thread has its own foo. Things will now
work as intended...
Basically dont use class member variables in your actions (unless you are
specifically intending to share information between threads with them. Even
in that case it would not be a good idea as you have other such
considerations as clustering, the need to synchronize reads and writes
etc...).

Now you may be thinking you could instead of refactoring all that code in
the first version of WotsitAction just make the execute & other public
methods synchronized, and indeed you technically could.

That however has nasty performance implications. Imagine the execute()
method takes 10 seconds to do its thing. Imagine also that 6 users submit at
once. With execute synchronized, only one of the threads can be executing
the synchronized code at a time. Some of those users could be waiting up to
a minute for their request to complete... Furthermore thread wakeup
notification doesnt happen in any particular order. If lots more requests
keep pouring in all the time its conceivable some request threads could
'never' get a chance to run execute()!!!!

These sort of issues need to be considered for any shared objects. For
example stuff you put into ServletContext can be accessed by many threads at
the same time. Likewise with stuff in the SessionContext. The request
context on the other hand is not shared with other threads (unless you make
your own threads - (dont do that in a webapp! - its naughty)). Request
scoped actionform instances are therefore unique to that request. Session
scoped actionforms may be 'problematic' under some circumstances. (Refer to
my discussion in this list with Eddie recently under the thread "Multiple
forms in session" to see why)

-----Original Message-----
From: Amit Badheka [mailto:amit@direct2s.com]
Sent: Friday, December 20, 2002 15:05
To: Struts Users Mailing List
Subject: multithreaded env


Hi All,

I am working on a struts application. But I am not sure that it will work
properly in multithreaded environment.

Can anybody suggest me what is the best way to make sure that application
work fine in such environment.

Thank You.


--
To unsubscribe, e-mail:   <mailto:struts-user-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:struts-user-help@jakarta.apache.org>


Mime
View raw message